--- /dev/null
+What:          /sys/firmware/memmap/
+Date:          June 2008
+Contact:       Bernhard Walle <bwalle@suse.de>
+Description:
+               On all platforms, the firmware provides a memory map which the
+               kernel reads. The resources from that memory map are registered
+               in the kernel resource tree and exposed to userspace via
+               /proc/iomem (together with other resources).
+
+               However, on most architectures that firmware-provided memory
+               map is modified afterwards by the kernel itself, either because
+               the kernel merges that memory map with other information or
+               just because the user overwrites that memory map via command
+               line.
+
+               kexec needs the raw firmware-provided memory map to setup the
+               parameter segment of the kernel that should be booted with
+               kexec. Also, the raw memory map is useful for debugging. For
+               that reason, /sys/firmware/memmap is an interface that provides
+               the raw memory map to userspace.
+
+               The structure is as follows: Under /sys/firmware/memmap there
+               are subdirectories with the number of the entry as their name:
+
+                       /sys/firmware/memmap/0
+                       /sys/firmware/memmap/1
+                       /sys/firmware/memmap/2
+                       /sys/firmware/memmap/3
+                       ...
+
+               The maximum depends on the number of memory map entries provided
+               by the firmware. The order is just the order that the firmware
+               provides.
+
+               Each directory contains three files:
+
+               start   : The start address (as hexadecimal number with the
+                         '0x' prefix).
+               end     : The end address, inclusive (regardless whether the
+                         firmware provides inclusive or exclusive ranges).
+               type    : Type of the entry as string. See below for a list of
+                         valid types.
+
+               So, for example:
+
+                       /sys/firmware/memmap/0/start
+                       /sys/firmware/memmap/0/end
+                       /sys/firmware/memmap/0/type
+                       /sys/firmware/memmap/1/start
+                       ...
+
+               Currently following types exist:
+
+                 - System RAM
+                 - ACPI Tables
+                 - ACPI Non-volatile Storage
+                 - reserved
+
+               Following shell snippet can be used to display that memory
+               map in a human-readable format:
+
+               -------------------- 8< ----------------------------------------
+                 #!/bin/bash
+                 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 ----------------------------------------
 
--- /dev/null
+/*
+ * linux/drivers/firmware/memmap.c
+ *  Copyright (C) 2008 SUSE LINUX Products GmbH
+ *  by Bernhard Walle <bwalle@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/firmware-map.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+
+/*
+ * Data types ------------------------------------------------------------------
+ */
+
+/*
+ * Firmware map entry. Because firmware memory maps are flat and not
+ * hierarchical, it's ok to organise them in a linked list. No parent
+ * information is necessary as for the resource tree.
+ */
+struct firmware_map_entry {
+       resource_size_t         start;  /* start of the memory range */
+       resource_size_t         end;    /* end of the memory range (incl.) */
+       const char              *type;  /* type of the memory range */
+       struct list_head        list;   /* entry for the linked list */
+       struct kobject          kobj;   /* kobject for each entry */
+};
+
+/*
+ * Forward declarations --------------------------------------------------------
+ */
+static ssize_t memmap_attr_show(struct kobject *kobj,
+                               struct attribute *attr, char *buf);
+static ssize_t start_show(struct firmware_map_entry *entry, char *buf);
+static ssize_t end_show(struct firmware_map_entry *entry, char *buf);
+static ssize_t type_show(struct firmware_map_entry *entry, char *buf);
+
+/*
+ * Static data -----------------------------------------------------------------
+ */
+
+struct memmap_attribute {
+       struct attribute attr;
+       ssize_t (*show)(struct firmware_map_entry *entry, char *buf);
+};
+
+struct memmap_attribute memmap_start_attr = __ATTR_RO(start);
+struct memmap_attribute memmap_end_attr   = __ATTR_RO(end);
+struct memmap_attribute memmap_type_attr  = __ATTR_RO(type);
+
+/*
+ * These are default attributes that are added for every memmap entry.
+ */
+static struct attribute *def_attrs[] = {
+       &memmap_start_attr.attr,
+       &memmap_end_attr.attr,
+       &memmap_type_attr.attr,
+       NULL
+};
+
+static struct sysfs_ops memmap_attr_ops = {
+       .show = memmap_attr_show,
+};
+
+static struct kobj_type memmap_ktype = {
+       .sysfs_ops      = &memmap_attr_ops,
+       .default_attrs  = def_attrs,
+};
+
+/*
+ * Registration functions ------------------------------------------------------
+ */
+
+/*
+ * Firmware memory map entries
+ */
+static LIST_HEAD(map_entries);
+
+/**
+ * Common implementation of firmware_map_add() and firmware_map_add_early()
+ * which expects a pre-allocated struct firmware_map_entry.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ * @entry: Pre-allocated (either kmalloc() or bootmem allocator), uninitialised
+ *         entry.
+ */
+static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
+                                 const char *type,
+                                 struct firmware_map_entry *entry)
+{
+       BUG_ON(start > end);
+
+       entry->start = start;
+       entry->end = end;
+       entry->type = type;
+       INIT_LIST_HEAD(&entry->list);
+       kobject_init(&entry->kobj, &memmap_ktype);
+
+       list_add_tail(&entry->list, &map_entries);
+
+       return 0;
+}
+
+/*
+ * See <linux/firmware-map.h> for documentation.
+ */
+int firmware_map_add(resource_size_t start, resource_size_t end,
+                    const char *type)
+{
+       struct firmware_map_entry *entry;
+
+       entry = kmalloc(sizeof(struct firmware_map_entry), GFP_ATOMIC);
+       WARN_ON(!entry);
+       if (!entry)
+               return -ENOMEM;
+
+       return firmware_map_add_entry(start, end, type, entry);
+}
+
+/*
+ * See <linux/firmware-map.h> for documentation.
+ */
+int __init firmware_map_add_early(resource_size_t start, resource_size_t end,
+                                 const char *type)
+{
+       struct firmware_map_entry *entry;
+
+       entry = alloc_bootmem_low(sizeof(struct firmware_map_entry));
+       WARN_ON(!entry);
+       if (!entry)
+               return -ENOMEM;
+
+       return firmware_map_add_entry(start, end, type, entry);
+}
+
+/*
+ * Sysfs functions -------------------------------------------------------------
+ */
+
+static ssize_t start_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->start);
+}
+
+static ssize_t end_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "0x%llx\n", entry->end);
+}
+
+static ssize_t type_show(struct firmware_map_entry *entry, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
+}
+
+#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
+#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
+
+static ssize_t memmap_attr_show(struct kobject *kobj,
+                               struct attribute *attr, char *buf)
+{
+       struct firmware_map_entry *entry = to_memmap_entry(kobj);
+       struct memmap_attribute *memmap_attr = to_memmap_attr(attr);
+
+       return memmap_attr->show(entry, buf);
+}
+
+/*
+ * Initialises stuff and adds the entries in the map_entries list to
+ * sysfs. Important is that firmware_map_add() and firmware_map_add_early()
+ * must be called before late_initcall.
+ */
+static int __init memmap_init(void)
+{
+       int i = 0;
+       struct firmware_map_entry *entry;
+       struct kset *memmap_kset;
+
+       memmap_kset = kset_create_and_add("memmap", NULL, firmware_kobj);
+       WARN_ON(!memmap_kset);
+       if (!memmap_kset)
+               return -ENOMEM;
+
+       list_for_each_entry(entry, &map_entries, list) {
+               entry->kobj.kset = memmap_kset;
+               kobject_add(&entry->kobj, NULL, "%d", i++);
+       }
+
+       return 0;
+}
+late_initcall(memmap_init);
+
 
--- /dev/null
+/*
+ * include/linux/firmware-map.h:
+ *  Copyright (C) 2008 SUSE LINUX Products GmbH
+ *  by Bernhard Walle <bwalle@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef _LINUX_FIRMWARE_MAP_H
+#define _LINUX_FIRMWARE_MAP_H
+
+#include <linux/list.h>
+#include <linux/kobject.h>
+
+/*
+ * provide a dummy interface if CONFIG_FIRMWARE_MEMMAP is disabled
+ */
+#ifdef CONFIG_FIRMWARE_MEMMAP
+
+/**
+ * Adds a firmware mapping entry. This function uses kmalloc() for memory
+ * allocation. Use firmware_map_add_early() if you want to use the bootmem
+ * allocator.
+ *
+ * That function must be called before late_initcall.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ *
+ * Returns 0 on success, or -ENOMEM if no memory could be allocated.
+ */
+int firmware_map_add(resource_size_t start, resource_size_t end,
+                    const char *type);
+
+/**
+ * Adds a firmware mapping entry. This function uses the bootmem allocator
+ * for memory allocation. Use firmware_map_add() if you want to use kmalloc().
+ *
+ * That function must be called before late_initcall.
+ *
+ * @start: Start of the memory range.
+ * @end:   End of the memory range (inclusive).
+ * @type:  Type of the memory range.
+ *
+ * Returns 0 on success, or -ENOMEM if no memory could be allocated.
+ */
+int firmware_map_add_early(resource_size_t start, resource_size_t end,
+                          const char *type);
+
+#else /* CONFIG_FIRMWARE_MEMMAP */
+
+static inline int firmware_map_add(resource_size_t start, resource_size_t end,
+                                  const char *type)
+{
+       return 0;
+}
+
+static inline int firmware_map_add_early(resource_size_t start,
+                                        resource_size_t end, const char *type)
+{
+       return 0;
+}
+
+#endif /* CONFIG_FIRMWARE_MEMMAP */
+
+#endif /* _LINUX_FIRMWARE_MAP_H */