bitkeeper revision 1.1159.201.1 (41ab6fa1bs5vtddKGV1tNJawdZEZdw)

New /dev/mem patch moves the Xen specifics out to an arch-specific
file. Read/writes of /dev/mem now access I/O space rather than kernel
space. Fixed ioremap.c a whole lot to now use the rather more robust
direct_remap_area_pages(). 'dmidecode' now works in DOM0. :-)
This commit is contained in:
kaf24@scramble.cl.cam.ac.uk committed 2004-11-29 18:51:13 +00:00
1 parent e0596851e8
commit cfb60f4ea0
6 files changed
+306 -214

No files matched your search

+1
View File
@@ -171,6 +171,7 @@
4107adf1s5u6249DNPUViX1YNagbUQ linux-2.6.9-xen-sparse/arch/xen/i386/pci/irq.c
40f56239zOksGg_H4XD4ye6iZNtoZA linux-2.6.9-xen-sparse/arch/xen/kernel/Makefile
40f56239bvOjuuuViZ0XMlNiREFC0A linux-2.6.9-xen-sparse/arch/xen/kernel/ctrl_if.c
41ab6fa06JdF7jxUsuDcjN3UhuIAxg linux-2.6.9-xen-sparse/arch/xen/kernel/devmem.c
40f56238xFQe9T7M_U_FItM-bZIpLw linux-2.6.9-xen-sparse/arch/xen/kernel/evtchn.c
4110f478aeQWllIN7J4kouAHiAqrPw linux-2.6.9-xen-sparse/arch/xen/kernel/fixup.c
412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.9-xen-sparse/arch/xen/kernel/gnttab.c
+134 -197
View File
@@ -16,23 +16,33 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#ifndef CONFIG_XEN_PHYSDEV_ACCESS
void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
{ return NULL; }
void * __ioremap(unsigned long phys_addr, unsigned long size,
unsigned long flags)
{
return NULL;
}
void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
{ return NULL; }
{
return NULL;
}
void iounmap(volatile void __iomem *addr)
{ }
{
}
void __init *bt_ioremap(unsigned long phys_addr, unsigned long size)
{ return NULL; }
{
return NULL;
}
void __init bt_iounmap(void *addr, unsigned long size)
{ }
{
}
#else
@@ -50,86 +60,6 @@ static inline int is_local_lowmem(unsigned long address)
return ((pfn < max_low_pfn) && (pfn_to_mfn(pfn) == mfn));
}
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
unsigned long end;
unsigned long pfn;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
if (address >= end)
BUG();
pfn = phys_addr >> PAGE_SHIFT;
do {
if (!pte_none(*pte)) {
printk("remap_area_pte: page already exists\n");
BUG();
}
set_pte(pte, pfn_pte_ma(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
_PAGE_DIRTY | _PAGE_ACCESSED | flags)));
address += PAGE_SIZE;
pfn++;
pte++;
} while (address && (address < end));
}
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
unsigned long end;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
phys_addr -= address;
if (address >= end)
BUG();
do {
pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
if (!pte)
return -ENOMEM;
remap_area_pte(pte, address, end - address, address + phys_addr, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0;
}
static int remap_area_pages(unsigned long address, unsigned long phys_addr,
unsigned long size, unsigned long flags)
{
int error;
pgd_t * dir;
unsigned long end = address + size;
phys_addr -= address;
dir = pgd_offset(&init_mm, address);
flush_cache_all();
if (address >= end)
BUG();
spin_lock(&init_mm.page_table_lock);
do {
pmd_t *pmd;
pmd = pmd_alloc(&init_mm, dir, address);
error = -ENOMEM;
if (!pmd)
break;
if (remap_area_pmd(pmd, address, end - address,
phys_addr + address, flags))
break;
error = 0;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
spin_unlock(&init_mm.page_table_lock);
flush_tlb_all();
return error;
}
/*
* Generic mapping function (not visible outside):
*/
@@ -192,7 +122,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
return NULL;
area->phys_addr = phys_addr;
addr = (void __iomem *) area->addr;
if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
if (direct_remap_area_pages(&init_mm, (unsigned long) addr, phys_addr, size, __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | flags), DOMID_IO)) {
vunmap((void __force *) addr);
return NULL;
}
@@ -360,138 +290,145 @@ void __init bt_iounmap(void *addr, unsigned long size)
#define direct_mk_pte_phys(physpage, pgprot) \
__direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot)
static inline void direct_remap_area_pte(pte_t *pte,
unsigned long address,
unsigned long size,
mmu_update_t **v)
static inline void direct_remap_area_pte(
pte_t *pte,
unsigned long address,
unsigned long size,
mmu_update_t **v)
{
unsigned long end;
unsigned long end;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
if (address >= end)
BUG();
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
if (address >= end)
BUG();
do {
(*v)->ptr = virt_to_machine(pte);
(*v)++;
address += PAGE_SIZE;
pte++;
} while (address && (address < end));
do {
(*v)->ptr = virt_to_machine(pte);
(*v)++;
address += PAGE_SIZE;
pte++;
} while (address && (address < end));
}
static inline int direct_remap_area_pmd(struct mm_struct *mm,
pmd_t *pmd,
unsigned long address,
unsigned long size,
mmu_update_t **v)
static inline int direct_remap_area_pmd(
struct mm_struct *mm,
pmd_t *pmd,
unsigned long address,
unsigned long size,
mmu_update_t **v)
{
unsigned long end;
unsigned long end;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
if (address >= end)
BUG();
do {
pte_t *pte = pte_alloc_map(mm, pmd, address);
if (!pte)
return -ENOMEM;
direct_remap_area_pte(pte, address, end - address, v);
pte_unmap(pte);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
if (address >= end)
BUG();
do {
pte_t *pte = (mm == &init_mm) ?
pte_alloc_kernel(mm, pmd, address) :
pte_alloc_map(mm, pmd, address);
if (!pte)
return -ENOMEM;
direct_remap_area_pte(pte, address, end - address, v);
pte_unmap(pte);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0;
}
int __direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long size,
mmu_update_t *v)
int __direct_remap_area_pages(
struct mm_struct *mm,
unsigned long address,
unsigned long size,
mmu_update_t *v)
{
pgd_t * dir;
unsigned long end = address + size;
pgd_t * dir;
unsigned long end = address + size;
dir = pgd_offset(mm, address);
flush_cache_all();
if (address >= end)
BUG();
spin_lock(&mm->page_table_lock);
do {
pmd_t *pmd = pmd_alloc(mm, dir, address);
if (!pmd)
return -ENOMEM;
direct_remap_area_pmd(mm, pmd, address, end - address, &v);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
dir = pgd_offset(mm, address);
if (address >= end)
BUG();
spin_lock(&mm->page_table_lock);
do {
pmd_t *pmd = pmd_alloc(mm, dir, address);
if (!pmd)
return -ENOMEM;
direct_remap_area_pmd(mm, pmd, address, end - address, &v);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
spin_unlock(&mm->page_table_lock);
flush_tlb_all();
return 0;
} while (address && (address < end));
spin_unlock(&mm->page_table_lock);
return 0;
}
int direct_remap_area_pages(struct mm_struct *mm,
unsigned long address,
unsigned long machine_addr,
unsigned long size,
pgprot_t prot,
domid_t domid)
int direct_remap_area_pages(
struct mm_struct *mm,
unsigned long address,
unsigned long machine_addr,
unsigned long size,
pgprot_t prot,
domid_t domid)
{
int i;
unsigned long start_address;
int i;
unsigned long start_address;
#define MAX_DIRECTMAP_MMU_QUEUE 130
mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *w, *v;
u[0].ptr = MMU_EXTENDED_COMMAND;
u[0].val = MMUEXT_SET_FOREIGNDOM;
u[0].val |= (unsigned long)domid << 16;
v = w = &u[1];
u[0].ptr = MMU_EXTENDED_COMMAND;
u[0].val = MMUEXT_SET_FOREIGNDOM;
u[0].val |= (unsigned long)domid << 16;
v = w = &u[1];
start_address = address;
start_address = address;
for( i = 0; i < size; i += PAGE_SIZE )
{
if ( (v - u) == MAX_DIRECTMAP_MMU_QUEUE )
{
/* Fill in the PTE pointers. */
__direct_remap_area_pages( mm,
start_address,
address-start_address,
w);
if ( HYPERVISOR_mmu_update(u, v - u, NULL) < 0 )
return -EFAULT;
v = w;
start_address = address;
flush_cache_all();
for (i = 0; i < size; i += PAGE_SIZE) {
if ((v - u) == MAX_DIRECTMAP_MMU_QUEUE) {
/* Fill in the PTE pointers. */
__direct_remap_area_pages(
mm,
start_address,
address-start_address,
w);
if (HYPERVISOR_mmu_update(u, v - u, NULL) < 0)
return -EFAULT;
v = w;
start_address = address;
}
/*
* Fill in the machine address: PTE ptr is done later by
* __direct_remap_area_pages().
*/
v->val = (machine_addr & PAGE_MASK) | pgprot_val(prot);
machine_addr += PAGE_SIZE;
address += PAGE_SIZE;
v++;
}
/*
* Fill in the machine address: PTE ptr is done later by
* __direct_remap_area_pages().
*/
v->val = (machine_addr & PAGE_MASK) | pgprot_val(prot);
if (v != w) {
/* get the ptep's filled in */
__direct_remap_area_pages(
mm,
start_address,
address-start_address,
w);
if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0))
return -EFAULT;
}
machine_addr += PAGE_SIZE;
address += PAGE_SIZE;
v++;
}
flush_tlb_all();
if ( v != w )
{
/* get the ptep's filled in */
__direct_remap_area_pages(mm,
start_address,
address-start_address,
w);
if ( unlikely(HYPERVISOR_mmu_update(u, v - u, NULL) < 0) )
return -EFAULT;
}
return 0;
return 0;
}
@@ -9,4 +9,4 @@ $(obj)/vmlinux.lds:
extra-y += vmlinux.lds
obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o
obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o devmem.o
@@ -0,0 +1,158 @@
/*
* Originally from linux/drivers/char/mem.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Added devfs support.
* Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
* Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
#include <linux/devfs_fs_kernel.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <asm/pgalloc.h>
#include <asm/uaccess.h>
#include <asm/io.h>
static inline int uncached_access(struct file *file, unsigned long addr)
{
if (file->f_flags & O_SYNC)
return 1;
/* Xen sets correct MTRR type on non-RAM for us. */
return 0;
}
/*
* 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 i, p = *ppos;
ssize_t read = 0;
void *v;
if ((v = ioremap(p, count)) == NULL) {
/*
* Some programs (e.g., dmidecode) groove off into weird RAM
* areas where no table scan 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. :-)
*/
for (i = 0; i < count; i++)
if (put_user(0, buf+i))
return -EFAULT;
return count;
}
if (copy_to_user(buf, v, count))
return -EFAULT;
iounmap(v);
read += count;
*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;
ssize_t written = 0;
void *v;
if ((v = ioremap(p, count)) == NULL)
return -EFAULT;
if (copy_to_user(v, buf, count))
return -EFAULT;
iounmap(v);
written += count;
*ppos += written;
return written;
}
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
int uncached;
uncached = uncached_access(file, offset);
if (uncached)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
/* Don't try to swap out physical pages.. */
vma->vm_flags |= VM_RESERVED;
/*
* Don't dump addresses that are not real memory to a core file.
*/
if (uncached)
vma->vm_flags |= VM_IO;
if (io_remap_page_range(vma, vma->vm_start, offset,
vma->vm_end-vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
}
/*
* 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;
down(&file->f_dentry->d_inode->i_sem);
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;
}
up(&file->f_dentry->d_inode->i_sem);
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,
};
+9 -16
View File
@@ -26,7 +26,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/pgalloc.h>
#ifdef CONFIG_IA64
# include <linux/efi.h>
@@ -43,12 +42,7 @@ extern void tapechar_init(void);
*/
static inline int uncached_access(struct file *file, unsigned long addr)
{
#ifdef CONFIG_XEN
if (file->f_flags & O_SYNC)
return 1;
/* Xen sets correct MTRR type on non-RAM for us. */
return 0;
#elif defined(__i386__)
#if defined(__i386__)
/*
* On the PPro and successors, the MTRRs are used to set
* memory types for physical addresses outside main memory,
@@ -149,7 +143,7 @@ static ssize_t do_write_mem(void *p, unsigned long realp,
return written;
}
#ifndef ARCH_HAS_DEV_MEM
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -195,8 +189,9 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
return -EFAULT;
return do_write_mem(__va(p), p, buf, count, ppos);
}
#endif
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
{
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
int uncached;
@@ -216,15 +211,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
if (uncached)
vma->vm_flags |= VM_IO;
#if defined(CONFIG_XEN)
if (io_remap_page_range(vma, vma->vm_start, offset,
vma->vm_end-vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
#else
if (remap_page_range(vma, vma->vm_start, offset, vma->vm_end-vma->vm_start,
vma->vm_page_prot))
return -EAGAIN;
#endif
return 0;
}
@@ -584,7 +573,7 @@ static int open_port(struct inode * inode, struct file * filp)
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
#define mmap_kmem mmap_mem
#define mmap_mem mmap_kmem
#define zero_lseek null_lseek
#define full_lseek null_lseek
#define write_zero write_null
@@ -592,6 +581,7 @@ static int open_port(struct inode * inode, struct file * filp)
#define open_mem open_port
#define open_kmem open_mem
#ifndef ARCH_HAS_DEV_MEM
static struct file_operations mem_fops = {
.llseek = memory_lseek,
.read = read_mem,
@@ -599,6 +589,9 @@ static struct file_operations mem_fops = {
.mmap = mmap_mem,
.open = open_mem,
};
#else
extern struct file_operations mem_fops;
#endif
static struct file_operations kmem_fops = {
.llseek = memory_lseek,
@@ -444,4 +444,7 @@ BUILDIO(b,b,char)
BUILDIO(w,w,short)
BUILDIO(l,,int)
/* We will be supplying our own /dev/mem implementation */
#define ARCH_HAS_DEV_MEM
#endif
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.