# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1163644863 -32400 # Node ID 5e6633732a9196c252150d36a9257603ba060cb3 # Parent ac5330d4945a6eb388424ba8cf76f494ad9df47a paraviatualize IA64 /dev/mem to use X. PATCHNAME: paravirtualize_dev_mem Signed-off-by: Isaku Yamahata diff -r ac5330d4945a -r 5e6633732a91 linux-2.6-xen-sparse/arch/ia64/xen/Makefile --- a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile Wed Nov 15 12:15:34 2006 -0700 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile Thu Nov 16 11:41:03 2006 +0900 @@ -4,6 +4,6 @@ obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \ hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \ - xcom_mini.o xcom_privcmd.o + xcom_mini.o xcom_privcmd.o mem.o pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o diff -r ac5330d4945a -r 5e6633732a91 linux-2.6-xen-sparse/arch/ia64/xen/mem.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/mem.c Thu Nov 16 11:41:03 2006 +0900 @@ -0,0 +1,281 @@ +/* + * Originally from linux/drivers/char/mem.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Added devfs support. + * Jan-11-1998, C. Scott Ananian + * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar + */ +/* + * taken from + * linux/drivers/char/mem.c and linux-2.6-xen-sparse/drivers/xen/char/mem.c. + * adjusted for IA64 and made transparent. + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Architectures vary in how they handle caching for addresses + * outside of main memory. + * + */ +static inline int uncached_access(struct file *file, unsigned long addr) +{ + /* + * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. + */ + return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); +} + +/* + * This funcion reads the *physical* memory. The f_pos points directly to the + * memory location. + */ +static ssize_t read_mem(struct file * file, char __user * buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos, ignored; + ssize_t read, sz; + unsigned long pfn; + void __iomem *v; + + if (!valid_phys_addr_range(p, &count)) + return -EFAULT; + + read = 0; + while (count > 0) { + /* + * Handle first page in case it's not aligned + */ + if (-p & (PAGE_SIZE - 1)) + sz = -p & (PAGE_SIZE - 1); + else + sz = PAGE_SIZE; + + sz = min_t(unsigned long, sz, count); + + /* + * On ia64 if a page has been mapped somewhere as + * uncached, then it must also be accessed uncached + * by the kernel or data corruption may occur + */ + /* + * vanilla linux uses xlate_dev_mem_ptr(), on xen + * however ioremap hypercall must be issued before + * touching io area. So we check it manually instead of + * xlate_dev_mem_ptr() + */ + pfn = p >> PAGE_SHIFT; + if (pfn_valid(pfn) && !PageUncached(pfn_to_page(pfn))) + ignored = copy_to_user(buf, __va(p), sz); + else { + v = ioremap(p, sz); + if (IS_ERR(v) || v == NULL) { + /* + * Some programs (e.g., dmidecode) groove off into weird RAM + * areas where no tables can possibly exist (because Xen will + * have stomped on them!). These programs get rather upset if + * we let them know that Xen failed their access, so we fake + * out a read of all zeroes. :-) + */ + if (clear_user(buf, count)) + return -EFAULT; + if (IS_ERR(v) && read == 0) + return PTR_ERR(v); + read += count; + break; + } + ignored = copy_to_user(buf, v, sz); + iounmap(v); + } + if (ignored) + return -EFAULT; + buf += sz; + p += sz; + count -= sz; + read += sz; + } + + *ppos += read; + return read; +} + +static ssize_t write_mem(struct file * file, const char __user * buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos, copied; + ssize_t written, sz; + void __iomem *v; + unsigned long pfn; + + if (!valid_phys_addr_range(p, &count)) + return -EFAULT; + + written = 0; + + while (count > 0) { + /* + * Handle first page in case it's not aligned + */ + if (-p & (PAGE_SIZE - 1)) + sz = -p & (PAGE_SIZE - 1); + else + sz = PAGE_SIZE; + + sz = min_t(unsigned long, sz, count); + + /* + * On ia64 if a page has been mapped somewhere as + * uncached, then it must also be accessed uncached + * by the kernel or data corruption may occur + */ + /* + * vanilla linux uses xlate_dev_mem_ptr(), on xen + * however ioremap hypercall must be issued before + * touching io area. So we check it manually instead of + * xlate_dev_mem_ptr() + */ + pfn = p >> PAGE_SHIFT; + if (pfn_valid(pfn) && !PageUncached(pfn_to_page(pfn))) + copied = copy_from_user(__va(p), buf, sz); + else { + v = ioremap(p, sz); + if (v == NULL) + break; + if (IS_ERR(v)) { + if (written == 0) + return PTR_ERR(v); + break; + } + + copied = copy_from_user(v, buf, sz); + iounmap(v); + } + if (copied) { + written += sz - copied; + if (written) + break; + return -EFAULT; + } + buf += sz; + p += sz; + count -= sz; + written += sz; + } + + *ppos += written; + return written; +} + +static int mmap_mem(struct file * file, struct vm_area_struct * vma) +{ + unsigned long addr = vma->vm_pgoff << PAGE_SHIFT; + size_t size = vma->vm_end - vma->vm_start; + + +#if 0 + /* + *XXX FIXME: linux-2.6.16.29, linux-2.6.17 + * valid_mmap_phys_addr_range() in linux/arch/ia64/kernel/efi.c + * fails checks. + * linux-2.6.18.1's returns always 1. + * Its comments says + * + * MMIO regions are often missing from the EFI memory map. + * We must allow mmap of them for programs like X, so we + * currently can't do any useful validation. + */ + if (!valid_mmap_phys_addr_range(addr, &size)) + return -EINVAL; + if (size < vma->vm_end - vma->vm_start) + return -EINVAL; +#endif + + if (is_running_on_xen()) { + unsigned long offset = HYPERVISOR_ioremap(addr, size); + if (IS_ERR_VALUE(offset)) + return offset; + } + + if (uncached_access(file, vma->vm_pgoff << PAGE_SHIFT)) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + size, + vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +/* + * The following two function is same as in linux/drivers/char/mem.c + */ +/* + * The memory devices use the full 32/64 bits of the offset, and so we cannot + * check against negative addresses: they are ok. The return value is weird, + * though, in that case (0). + * + * also note that seeking relative to the "end of file" isn't supported: + * it has no meaning, so it returns -EINVAL. + */ +static loff_t memory_lseek(struct file * file, loff_t offset, int orig) +{ + loff_t ret; + + mutex_lock(&file->f_dentry->d_inode->i_mutex); + switch (orig) { + case 0: + file->f_pos = offset; + ret = file->f_pos; + force_successful_syscall_return(); + break; + case 1: + file->f_pos += offset; + ret = file->f_pos; + force_successful_syscall_return(); + break; + default: + ret = -EINVAL; + } + mutex_unlock(&file->f_dentry->d_inode->i_mutex); + return ret; +} + +static int open_mem(struct inode * inode, struct file * filp) +{ + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +} + +struct file_operations mem_fops = { + .llseek = memory_lseek, + .read = read_mem, + .write = write_mem, + .mmap = mmap_mem, + .open = open_mem, +}; diff -r ac5330d4945a -r 5e6633732a91 linux-2.6-xen-sparse/include/asm-ia64/io.h --- a/linux-2.6-xen-sparse/include/asm-ia64/io.h Wed Nov 15 12:15:34 2006 -0700 +++ b/linux-2.6-xen-sparse/include/asm-ia64/io.h Thu Nov 16 11:41:03 2006 +0900 @@ -129,6 +129,9 @@ extern int valid_mmap_phys_addr_range (u (((bvec_to_bus((vec1)) + (vec1)->bv_len) == bvec_to_bus((vec2))) && \ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \ bvec_to_pseudophys((vec2)))) + +/* We will be supplying our own /dev/mem implementation */ +#define ARCH_HAS_DEV_MEM #endif /* CONFIG_XEN */ # endif /* KERNEL */ @@ -458,6 +461,8 @@ ioremap (unsigned long offset, unsigned ioremap (unsigned long offset, unsigned long size) { offset = HYPERVISOR_ioremap(offset, size); + if (IS_ERR_VALUE(offset)) + return (void __iomem*)offset; return (void __iomem *) (__IA64_UNCACHED_OFFSET | (offset)); }