Hi, Eric and all

Attached is an implementation of /proc/cpumem.
/proc/cpumem shows the valid physical memory ranges.

* i386 and x86_64
* implement valid_phys_addr_range() and use it.
  (the first argument of the i386 version is little uncomfortable.)
* /dev/mem of the i386 version should be mofified. but not yet.

example: amd64 8GB Mem
# cat /proc/cpumem
0000000000000000 000000000009b800
0000000000100000 00000000fbe70000
0000000100000000 0000000100000000
#
start address and size. hex digit.

Any comments, recomendations and suggestions are welcom.

BTW, does not kexec/kdump run on 2.6.11-rc3-mm2 ?
How do I get and examine the latest kexec/kdump ?

Thanks.
-- 
Itsuro ODA <[EMAIL PROTECTED]>

---
--- linux-2.6.11-rc3-mm2/drivers/char/mem.c     2005-02-16 15:36:31.000000000 
+0900
+++ linux-2.6.11-rc3-mm2-test/drivers/char/mem.c        2005-02-16 
23:32:15.244876816 +0900
@@ -25,6 +25,9 @@
 #include <linux/device.h>
 #include <linux/highmem.h>
 #include <linux/crash_dump.h>
+#include <linux/bootmem.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -759,3 +762,125 @@
 }
 
 fs_initcall(chr_dev_init);
+
+#ifdef CONFIG_PROC_FS
+/*
+ *  /proc/cpumem: show valid physical address range
+ */
+struct cpumem_info {
+       unsigned long long addr;
+       unsigned long long size;
+};
+
+static void *cpumem_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       struct cpumem_info *p = m->private;
+       unsigned long long end = (unsigned long long)max_pfn << PAGE_SHIFT;
+       unsigned long long addr;
+       size_t size;
+       int found = 0;
+
+       (*pos)++;
+
+       if (p->addr >= end) {
+               return NULL;
+       }
+
+       /* always start page boundary */
+       addr = ((p->addr + p->size + PAGE_SIZE - 1) >> PAGE_SHIFT) << 
PAGE_SHIFT;
+       size = 0xf0000000;
+
+       while (addr < end) {
+               if (valid_phys_addr_range(addr, &size)) {
+                       if (!found) {
+                               found = 1;
+                               p->addr = addr;
+                               p->size = size;
+                       } else {
+                               p->size += size;
+                       }
+                       addr += size;
+                       size = 0xf0000000;
+               } else {
+                       if (found) {
+                               return p;
+                       }
+                       addr += PAGE_SIZE;
+               }
+       }
+
+       return found ? p : NULL;
+}
+
+static void *cpumem_start(struct seq_file *m, loff_t *pos)
+{
+       struct cpumem_info *p = m->private;
+       loff_t n = 0;
+
+       p->addr = 0;
+       p->size = 0;
+
+       while (n <= *pos) {
+               if (!cpumem_next(m, NULL, &n)) {
+                       return NULL;
+               }
+       }
+
+       return p;
+}
+
+static void cpumem_stop(struct seq_file *m, void *v)
+{
+}
+
+static int cpumem_show(struct seq_file *m, void *v)
+{
+       struct cpumem_info *p = m->private;
+       unsigned long long end = (unsigned long long)max_pfn << PAGE_SHIFT;
+
+       if (p->addr < end) {
+               seq_printf(m, "%016llx %016llx\n", p->addr, p->size);
+       }
+       return 0;
+}
+
+struct seq_operations cpumem_op = {
+       .start  = cpumem_start,
+       .next   = cpumem_next,
+       .stop   = cpumem_stop,
+       .show   = cpumem_show
+};
+
+static int cpumem_open(struct inode *inode, struct file *file)
+{
+       int res = seq_open(file, &cpumem_op);
+       if (!res) {
+               struct seq_file *m = file->private_data;
+               m->private = kmalloc(sizeof(struct cpumem_info), GFP_KERNEL);
+               if (!m->private) {
+                       seq_release(inode, file);
+                       return -ENOMEM;
+               }
+       }
+       return res;
+}
+
+static struct file_operations proc_cpumem_operations = {
+       .open           = cpumem_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = seq_release_private
+};
+
+static int __init cpumem_init(void)
+{
+       struct proc_dir_entry *entry;
+
+       entry = create_proc_entry("cpumem", 0, NULL);
+       if (entry) {
+               entry->proc_fops = &proc_cpumem_operations;
+       }
+       return 0;
+}
+__initcall(cpumem_init);
+#endif /* CONFIG_PROC_FS */

---
--- linux-2.6.11-rc3-mm2/arch/i386/mm/init.c    2005-02-16 15:36:29.000000000 
+0900
+++ linux-2.6.11-rc3-mm2-test/arch/i386/mm/init.c       2005-02-16 
23:32:29.499709752 +0900
@@ -248,6 +248,47 @@
        return 0;
 }
 
+int valid_phys_addr_range(unsigned long long phys_addr, size_t *size)
+{
+       int i;
+       unsigned long long addr, end;
+       efi_memory_desc_t *md;
+
+       if (efi_enabled) {
+               for (i = 0; i < memmap.nr_map; i++) {
+                       md = &memmap.map[i];
+                       if (!is_available_memory(md)) {
+                               continue;
+                       }
+                       addr = md->phys_addr;
+                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
+                       if ((phys_addr >= addr) && (phys_addr < end)) {
+                               if (*size > end - phys_addr) {
+                                       *size = end - phys_addr;
+                               }
+                               return 1;
+                       }
+               }
+               return 0;
+       }
+
+       for (i = 0; i < e820.nr_map; i++) {
+               if (e820.map[i].type != E820_RAM) {
+                       continue;
+               }
+               addr = e820.map[i].addr;
+               end = e820.map[i].addr + e820.map[i].size;
+               if ((phys_addr >= addr) && (phys_addr < end)) {
+                       if (*size > end - phys_addr) {
+                               *size = end - phys_addr;
+                       }
+                       return 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(valid_phys_addr_range);
+
 #ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
 pgprot_t kmap_prot;

---
--- linux-2.6.11-rc3-mm2/include/asm-i386/io.h  2004-12-25 06:35:40.000000000 
+0900
+++ linux-2.6.11-rc3-mm2-test/include/asm-i386/io.h     2005-02-16 
23:36:24.454991120 +0900
@@ -90,6 +90,12 @@
  */
 #define page_to_phys(page)    ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 
+/*
+ * for /dev/mem
+ */
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern int valid_phys_addr_range(unsigned long long, size_t *);
+
 extern void __iomem * __ioremap(unsigned long offset, unsigned long size, 
unsigned long flags);
 
 /**

---
--- linux-2.6.11-rc3-mm2/arch/x86_64/mm/init.c  2005-02-16 15:36:30.000000000 
+0900
+++ linux-2.6.11-rc3-mm2-test/arch/x86_64/mm/init.c     2005-02-16 
16:23:08.000000000 +0900
@@ -22,6 +22,7 @@
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
 #include <linux/proc_fs.h>
+#include <linux/module.h>
 
 #include <asm/processor.h>
 #include <asm/system.h>
@@ -395,6 +396,27 @@
        return 0;
 }
 
+int valid_phys_addr_range(unsigned long phys_addr, size_t *size)
+{
+       int i;
+       unsigned long end;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               if (e820.map[i].type != E820_RAM) {
+                       continue;
+               }
+               end = e820.map[i].addr + e820.map[i].size;
+               if (phys_addr >= e820.map[i].addr && phys_addr < end) {
+                       if (*size > end - phys_addr) {
+                               *size = end - phys_addr;
+                       }
+                       return 1;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(valid_phys_addr_range);
+
 extern int swiotlb_force;
 
 /*

---
--- linux-2.6.11-rc3-mm2/include/asm-x86_64/io.h        2005-02-16 
15:36:12.000000000 +0900
+++ linux-2.6.11-rc3-mm2-test/include/asm-x86_64/io.h   2005-02-16 
16:23:59.000000000 +0900
@@ -123,6 +123,9 @@
 {
        return __va(address);
 }
+
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern int valid_phys_addr_range(unsigned long, size_t *);
 #endif
 
 /*

---

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to