lkml.org 
[lkml]   [2005]   [Feb]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patches in this message
    /
    Date
    From
    Subject[PATCH] /proc/cpumem
    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 <oda@valinux.co.jp>

    ---
    --- 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 majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:10    [W:0.038 / U:60.904 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site