aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernhard Walle <bwalle@suse.de>2008-06-27 07:12:54 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-08 11:55:41 -0400
commit69ac9cd629ca96e59f34eb4ccd12d00b2c8276a7 (patch)
treee9bb108c5ec36c666d64a52ca35ccf0197c84306
parent6247943d8ab699b57653afd453a4940cca70ef8a (diff)
sysfs: add /sys/firmware/memmap
This patch adds /sys/firmware/memmap interface that represents the BIOS (or Firmware) provided memory map. The tree looks like: /sys/firmware/memmap/0/start (hex number) end (hex number) type (string) ... /1/start end type With the following shell snippet one can print the memory map in the same form the kernel prints itself when booting on x86 (the E820 map). --------- 8< -------------------------- #!/bin/sh cd /sys/firmware/memmap for dir in * ; do start=$(cat $dir/start) end=$(cat $dir/end) type=$(cat $dir/type) printf "%016x-%016x (%s)\n" $start $[ $end +1] "$type" done --------- >8 -------------------------- That patch only provides the needed interface: 1. The sysfs interface. 2. The structure and enumeration definition. 3. The function firmware_map_add() and firmware_map_add_early() that should be called from architecture code (E820/EFI, for example) to add the contents to the interface. If the kernel is compiled without CONFIG_FIRMWARE_MEMMAP, the interface does nothing without cluttering the architecture-specific code with #ifdef's. The purpose of the new interface is kexec: While /proc/iomem represents the *used* memory map (e.g. modified via kernel parameters like 'memmap' and 'mem'), the /sys/firmware/memmap tree represents the unmodified memory map provided via the firmware. So kexec can: - use the original memory map for rebooting, - use the /proc/iomem for setting up the ELF core headers for kdump case that should only represent the memory of the system. The patch has been tested on i386 and x86_64. Signed-off-by: Bernhard Walle <bwalle@suse.de> Acked-by: Greg KH <gregkh@suse.de> Acked-by: Vivek Goyal <vgoyal@redhat.com> Cc: kexec@lists.infradead.org Cc: yhlu.kernel@gmail.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-memmap71
-rw-r--r--drivers/firmware/Kconfig10
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/memmap.c205
-rw-r--r--include/linux/firmware-map.h74
5 files changed, 361 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-firmware-memmap b/Documentation/ABI/testing/sysfs-firmware-memmap
new file mode 100644
index 000000000000..0d99ee6ae02e
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-memmap
@@ -0,0 +1,71 @@
1What: /sys/firmware/memmap/
2Date: June 2008
3Contact: Bernhard Walle <bwalle@suse.de>
4Description:
5 On all platforms, the firmware provides a memory map which the
6 kernel reads. The resources from that memory map are registered
7 in the kernel resource tree and exposed to userspace via
8 /proc/iomem (together with other resources).
9
10 However, on most architectures that firmware-provided memory
11 map is modified afterwards by the kernel itself, either because
12 the kernel merges that memory map with other information or
13 just because the user overwrites that memory map via command
14 line.
15
16 kexec needs the raw firmware-provided memory map to setup the
17 parameter segment of the kernel that should be booted with
18 kexec. Also, the raw memory map is useful for debugging. For
19 that reason, /sys/firmware/memmap is an interface that provides
20 the raw memory map to userspace.
21
22 The structure is as follows: Under /sys/firmware/memmap there
23 are subdirectories with the number of the entry as their name:
24
25 /sys/firmware/memmap/0
26 /sys/firmware/memmap/1
27 /sys/firmware/memmap/2
28 /sys/firmware/memmap/3
29 ...
30
31 The maximum depends on the number of memory map entries provided
32 by the firmware. The order is just the order that the firmware
33 provides.
34
35 Each directory contains three files:
36
37 start : The start address (as hexadecimal number with the
38 '0x' prefix).
39 end : The end address, inclusive (regardless whether the
40 firmware provides inclusive or exclusive ranges).
41 type : Type of the entry as string. See below for a list of
42 valid types.
43
44 So, for example:
45
46 /sys/firmware/memmap/0/start
47 /sys/firmware/memmap/0/end
48 /sys/firmware/memmap/0/type
49 /sys/firmware/memmap/1/start
50 ...
51
52 Currently following types exist:
53
54 - System RAM
55 - ACPI Tables
56 - ACPI Non-volatile Storage
57 - reserved
58
59 Following shell snippet can be used to display that memory
60 map in a human-readable format:
61
62 -------------------- 8< ----------------------------------------
63 #!/bin/bash
64 cd /sys/firmware/memmap
65 for dir in * ; do
66 start=$(cat $dir/start)
67 end=$(cat $dir/end)
68 type=$(cat $dir/type)
69 printf "%016x-%016x (%s)\n" $start $[ $end +1] "$type"
70 done
71 -------------------- >8 ----------------------------------------
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index dc2cec6127d1..ebb9e51deb0c 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -26,6 +26,16 @@ config EDD_OFF
26 kernel. Say N if you want EDD enabled by default. EDD can be dynamically set 26 kernel. Say N if you want EDD enabled by default. EDD can be dynamically set
27 using the kernel parameter 'edd={on|skipmbr|off}'. 27 using the kernel parameter 'edd={on|skipmbr|off}'.
28 28
29config FIRMWARE_MEMMAP
30 bool "Add firmware-provided memory map to sysfs" if EMBEDDED
31 default (X86_64 || X86_32)
32 help
33 Add the firmware-provided (unmodified) memory map to /sys/firmware/memmap.
34 That memory map is used for example by kexec to set up parameter area
35 for the next kernel, but can also be used for debugging purposes.
36
37 See also Documentation/ABI/testing/sysfs-firmware-memmap.
38
29config EFI_VARS 39config EFI_VARS
30 tristate "EFI Variable Support via sysfs" 40 tristate "EFI Variable Support via sysfs"
31 depends on EFI 41 depends on EFI
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 4c9147154df8..1c3c17343dbe 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o
10obj-$(CONFIG_DMIID) += dmi-id.o 10obj-$(CONFIG_DMIID) += dmi-id.o
11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o 11obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o 12obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
13obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c
new file mode 100644
index 000000000000..e23399c7f773
--- /dev/null
+++ b/drivers/firmware/memmap.c
@@ -0,0 +1,205 @@
1/*
2 * linux/drivers/firmware/memmap.c
3 * Copyright (C) 2008 SUSE LINUX Products GmbH
4 * by Bernhard Walle <bwalle@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License v2.0 as published by
8 * the Free Software Foundation
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/string.h>
18#include <linux/firmware-map.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/types.h>
22#include <linux/bootmem.h>
23
24/*
25 * Data types ------------------------------------------------------------------
26 */
27
28/*
29 * Firmware map entry. Because firmware memory maps are flat and not
30 * hierarchical, it's ok to organise them in a linked list. No parent
31 * information is necessary as for the resource tree.
32 */
33struct firmware_map_entry {
34 resource_size_t start; /* start of the memory range */
35 resource_size_t end; /* end of the memory range (incl.) */
36 const char *type; /* type of the memory range */
37 struct list_head list; /* entry for the linked list */
38 struct kobject kobj; /* kobject for each entry */
39};
40
41/*
42 * Forward declarations --------------------------------------------------------
43 */
44static ssize_t memmap_attr_show(struct kobject *kobj,
45 struct attribute *attr, char *buf);
46static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
47static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
48static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
49
50/*
51 * Static data -----------------------------------------------------------------
52 */
53
54struct memmap_attribute {
55 struct attribute attr;
56 ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
57};
58
59struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
60struct memmap_attribute memmap_end_attr = __ATTR_RO(end);
61struct memmap_attribute memmap_type_attr = __ATTR_RO(type);
62
63/*
64 * These are default attributes that are added for every memmap entry.
65 */
66static struct attribute *def_attrs[] = {
67 &memmap_start_attr.attr,
68 &memmap_end_attr.attr,
69 &memmap_type_attr.attr,
70 NULL
71};
72
73static struct sysfs_ops memmap_attr_ops = {
74 .show = memmap_attr_show,
75};
76
77static struct kobj_type memmap_ktype = {
78 .sysfs_ops = &memmap_attr_ops,
79 .default_attrs = def_attrs,
80};
81
82/*
83 * Registration functions ------------------------------------------------------
84 */
85
86/*
87 * Firmware memory map entries
88 */
89static LIST_HEAD(map_entries);
90
91/**
92 * Common implementation of firmware_map_add() and firmware_map_add_early()
93 * which expects a pre-allocated struct firmware_map_entry.
94 *
95 * @start: Start of the memory range.
96 * @end: End of the memory range (inclusive).
97 * @type: Type of the memory range.
98 * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised
99 * entry.
100 */
101static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
102 const char *type,
103 struct firmware_map_entry *entry)
104{
105 BUG_ON(start > end);
106
107 entry->start = start;
108 entry->end = end;
109 entry->type = type;
110 INIT_LIST_HEAD(&entry->list);
111 kobject_init(&entry->kobj, &memmap_ktype);
112
113 list_add_tail(&entry->list, &map_entries);
114
115 return 0;
116}
117
118/*
119 * See <linux/firmware-map.h> for documentation.
120 */
121int firmware_map_add(resource_size_t start, resource_size_t end,
122 const char *type)
123{
124 struct firmware_map_entry *entry;
125
126 entry = kmalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
127 WARN_ON(!entry);
128 if (!entry)
129 return -ENOMEM;
130
131 return firmware_map_add_entry(start, end, type, entry);
132}
133
134/*
135 * See <linux/firmware-map.h> for documentation.
136 */
137int __init firmware_map_add_early(resource_size_t start, resource_size_t end,
138 const char *type)
139{
140 struct firmware_map_entry *entry;
141
142 entry = alloc_bootmem_low(sizeof(struct firmware_map_entry));
143 WARN_ON(!entry);
144 if (!entry)
145 return -ENOMEM;
146
147 return firmware_map_add_entry(start, end, type, entry);
148}
149
150/*
151 * Sysfs functions -------------------------------------------------------------
152 */
153
154static ssize_t start_show(struct firmware_map_entry *entry, char *buf)
155{
156 return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->start);
157}
158
159static ssize_t end_show(struct firmware_map_entry *entry, char *buf)
160{
161 return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->end);
162}
163
164static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
165{
166 return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
167}
168
169#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
170#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
171
172static ssize_t memmap_attr_show(struct kobject *kobj,
173 struct attribute *attr, char *buf)
174{
175 struct firmware_map_entry *entry = to_memmap_entry(kobj);
176 struct memmap_attribute *memmap_attr = to_memmap_attr(attr);
177
178 return memmap_attr->show(entry, buf);
179}
180
181/*
182 * Initialises stuff and adds the entries in the map_entries list to
183 * sysfs. Important is that firmware_map_add() and firmware_map_add_early()
184 * must be called before late_initcall.
185 */
186static int __init memmap_init(void)
187{
188 int i = 0;
189 struct firmware_map_entry *entry;
190 struct kset *memmap_kset;
191
192 memmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
193 WARN_ON(!memmap_kset);
194 if (!memmap_kset)
195 return -ENOMEM;
196
197 list_for_each_entry(entry, &map_entries, list) {
198 entry->kobj.kset = memmap_kset;
199 kobject_add(&entry->kobj, NULL, "%d", i++);
200 }
201
202 return 0;
203}
204late_initcall(memmap_init);
205
diff --git a/include/linux/firmware-map.h b/include/linux/firmware-map.h
new file mode 100644
index 000000000000..acbdbcc16051
--- /dev/null
+++ b/include/linux/firmware-map.h
@@ -0,0 +1,74 @@
1/*
2 * include/linux/firmware-map.h:
3 * Copyright (C) 2008 SUSE LINUX Products GmbH
4 * by Bernhard Walle <bwalle@suse.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License v2.0 as published by
8 * the Free Software Foundation
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16#ifndef _LINUX_FIRMWARE_MAP_H
17#define _LINUX_FIRMWARE_MAP_H
18
19#include <linux/list.h>
20#include <linux/kobject.h>
21
22/*
23 * provide a dummy interface if CONFIG_FIRMWARE_MEMMAP is disabled
24 */
25#ifdef CONFIG_FIRMWARE_MEMMAP
26
27/**
28 * Adds a firmware mapping entry. This function uses kmalloc() for memory
29 * allocation. Use firmware_map_add_early() if you want to use the bootmem
30 * allocator.
31 *
32 * That function must be called before late_initcall.
33 *
34 * @start: Start of the memory range.
35 * @end: End of the memory range (inclusive).
36 * @type: Type of the memory range.
37 *
38 * Returns 0 on success, or -ENOMEM if no memory could be allocated.
39 */
40int firmware_map_add(resource_size_t start, resource_size_t end,
41 const char *type);
42
43/**
44 * Adds a firmware mapping entry. This function uses the bootmem allocator
45 * for memory allocation. Use firmware_map_add() if you want to use kmalloc().
46 *
47 * That function must be called before late_initcall.
48 *
49 * @start: Start of the memory range.
50 * @end: End of the memory range (inclusive).
51 * @type: Type of the memory range.
52 *
53 * Returns 0 on success, or -ENOMEM if no memory could be allocated.
54 */
55int firmware_map_add_early(resource_size_t start, resource_size_t end,
56 const char *type);
57
58#else /* CONFIG_FIRMWARE_MEMMAP */
59
60static inline int firmware_map_add(resource_size_t start, resource_size_t end,
61 const char *type)
62{
63 return 0;
64}
65
66static inline int firmware_map_add_early(resource_size_t start,
67 resource_size_t end, const char *type)
68{
69 return 0;
70}
71
72#endif /* CONFIG_FIRMWARE_MEMMAP */
73
74#endif /* _LINUX_FIRMWARE_MAP_H */