Commit 7200ebc9 authored by Paul Mackerras's avatar Paul Mackerras

Merge samba.org:/home/paulus/kernel/linux-2.5

into samba.org:/home/paulus/kernel/for-linus-ppc
parents ecad4a56 83ca4c7e
...@@ -115,8 +115,8 @@ DRIVERS-y := ...@@ -115,8 +115,8 @@ DRIVERS-y :=
DRIVERS-m := DRIVERS-m :=
DRIVERS- := DRIVERS- :=
DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o
DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
DRIVERS-y += drivers/base/base.o \ DRIVERS-y += drivers/base/base.o \
drivers/char/char.o \ drivers/char/char.o \
......
...@@ -182,26 +182,19 @@ checkCPUtype: ...@@ -182,26 +182,19 @@ checkCPUtype:
pushfl # push EFLAGS pushfl # push EFLAGS
popl %eax # get EFLAGS popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS movl %eax,%ecx # save original EFLAGS
xorl $0x40000,%eax # flip AC bit in EFLAGS xorl $0x240000,%eax # flip AC and ID bits in EFLAGS
pushl %eax # copy to EFLAGS pushl %eax # copy to EFLAGS
popfl # set EFLAGS popfl # set EFLAGS
pushfl # get new EFLAGS pushfl # get new EFLAGS
popl %eax # put it in eax popl %eax # put it in eax
xorl %ecx,%eax # change in flags xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed pushl %ecx # restore original EFLAGS
popfl
testl $0x40000,%eax # check if AC bit changed
je is386 je is386
movb $4,X86 # at least 486 movb $4,X86 # at least 486
movl %ecx,%eax testl $0x200000,%eax # check if ID bit changed
xorl $0x200000,%eax # check ID flag
pushl %eax
popfl # if we are on a straight 486DX, SX, or
pushfl # 487SX we can't change it
popl %eax
xorl %ecx,%eax
pushl %ecx # restore original EFLAGS
popfl
andl $0x200000,%eax
je is486 je is486
/* get vendor info */ /* get vendor info */
...@@ -227,18 +220,15 @@ checkCPUtype: ...@@ -227,18 +220,15 @@ checkCPUtype:
movb %cl,X86_MASK movb %cl,X86_MASK
movl %edx,X86_CAPABILITY movl %edx,X86_CAPABILITY
is486: is486: movl $0x50022,%ecx # set AM, WP, NE and MP
movl %cr0,%eax # 486 or better
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x50022,%eax # set AM, WP, NE and MP
jmp 2f jmp 2f
is386: pushl %ecx # restore original EFLAGS is386: movl $2,%ecx # set MP
popfl 2: movl %cr0,%eax
movl %cr0,%eax # 386
andl $0x80000011,%eax # Save PG,PE,ET andl $0x80000011,%eax # Save PG,PE,ET
orl $2,%eax # set MP orl %ecx,%eax
2: movl %eax,%cr0 movl %eax,%cr0
call check_x87 call check_x87
incb ready incb ready
lgdt gdt_descr lgdt gdt_descr
......
...@@ -174,3 +174,5 @@ EXPORT_SYMBOL(atomic_dec_and_lock); ...@@ -174,3 +174,5 @@ EXPORT_SYMBOL(atomic_dec_and_lock);
extern int is_sony_vaio_laptop; extern int is_sony_vaio_laptop;
EXPORT_SYMBOL(is_sony_vaio_laptop); EXPORT_SYMBOL(is_sony_vaio_laptop);
EXPORT_SYMBOL(__PAGE_KERNEL);
...@@ -177,71 +177,52 @@ static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t ...@@ -177,71 +177,52 @@ static void __init fixrange_init (unsigned long start, unsigned long end, pgd_t
} }
} }
unsigned long __PAGE_KERNEL = _PAGE_KERNEL;
static void __init pagetable_init (void) static void __init pagetable_init (void)
{ {
unsigned long vaddr, end; unsigned long vaddr, pfn;
pgd_t *pgd, *pgd_base; pgd_t *pgd, *pgd_base;
int i, j, k; int i, j, k;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte, *pte_base; pte_t *pte, *pte_base;
/*
* This can be zero as well - no problem, in that case we exit
* the loops anyway due to the PTRS_PER_* conditions.
*/
end = (unsigned long)__va(max_low_pfn*PAGE_SIZE);
pgd_base = swapper_pg_dir; pgd_base = swapper_pg_dir;
#if CONFIG_X86_PAE #if CONFIG_X86_PAE
for (i = 0; i < PTRS_PER_PGD; i++) for (i = 0; i < PTRS_PER_PGD; i++)
set_pgd(pgd_base + i, __pgd(1 + __pa(empty_zero_page))); set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
#endif #endif
if (cpu_has_pse) {
set_in_cr4(X86_CR4_PSE);
}
if (cpu_has_pge) {
set_in_cr4(X86_CR4_PGE);
__PAGE_KERNEL |= _PAGE_GLOBAL;
}
i = __pgd_offset(PAGE_OFFSET); i = __pgd_offset(PAGE_OFFSET);
pfn = 0;
pgd = pgd_base + i; pgd = pgd_base + i;
for (; i < PTRS_PER_PGD; pgd++, i++) { for (; i < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, i++) {
vaddr = i*PGDIR_SIZE;
if (end && (vaddr >= end))
break;
#if CONFIG_X86_PAE #if CONFIG_X86_PAE
pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); pmd = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
set_pgd(pgd, __pgd(__pa(pmd) + 0x1)); set_pgd(pgd, __pgd(__pa(pmd) | _PAGE_PRESENT));
#else #else
pmd = (pmd_t *)pgd; pmd = (pmd_t *) pgd;
#endif #endif
if (pmd != pmd_offset(pgd, 0)) for (j = 0; j < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, j++) {
BUG();
for (j = 0; j < PTRS_PER_PMD; pmd++, j++) {
vaddr = i*PGDIR_SIZE + j*PMD_SIZE;
if (end && (vaddr >= end))
break;
if (cpu_has_pse) { if (cpu_has_pse) {
unsigned long __pe; set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
pfn += PTRS_PER_PTE;
set_in_cr4(X86_CR4_PSE); } else {
boot_cpu_data.wp_works_ok = 1; pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
__pe = _KERNPG_TABLE + _PAGE_PSE + __pa(vaddr);
/* Make it "global" too if supported */
if (cpu_has_pge) {
set_in_cr4(X86_CR4_PGE);
__pe += _PAGE_GLOBAL;
}
set_pmd(pmd, __pmd(__pe));
continue;
}
pte_base = pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); for (k = 0; k < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, k++)
set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
for (k = 0; k < PTRS_PER_PTE; pte++, k++) { set_pmd(pmd, __pmd(__pa(pte_base) | _KERNPG_TABLE));
vaddr = i*PGDIR_SIZE + j*PMD_SIZE + k*PAGE_SIZE;
if (end && (vaddr >= end))
break;
*pte = pfn_pte(__pa(vaddr) >> PAGE_SHIFT, PAGE_KERNEL);
} }
set_pmd(pmd, __pmd(_KERNPG_TABLE + __pa(pte_base)));
if (pte_base != pte_offset_kernel(pmd, 0))
BUG();
} }
} }
...@@ -358,14 +339,17 @@ static int do_test_wp_bit(unsigned long vaddr); ...@@ -358,14 +339,17 @@ static int do_test_wp_bit(unsigned long vaddr);
void __init test_wp_bit(void) void __init test_wp_bit(void)
{ {
/*
* Ok, all PSE-capable CPUs are definitely handling the WP bit right.
*/
const unsigned long vaddr = PAGE_OFFSET; const unsigned long vaddr = PAGE_OFFSET;
pgd_t *pgd; pgd_t *pgd;
pmd_t *pmd; pmd_t *pmd;
pte_t *pte, old_pte; pte_t *pte, old_pte;
if (cpu_has_pse) {
/* Ok, all PSE-capable CPUs are definitely handling the WP bit right. */
boot_cpu_data.wp_works_ok = 1;
return;
}
printk("Checking if this processor honours the WP bit even in supervisor mode... "); printk("Checking if this processor honours the WP bit even in supervisor mode... ");
pgd = swapper_pg_dir + __pgd_offset(vaddr); pgd = swapper_pg_dir + __pgd_offset(vaddr);
......
O_TARGET := base.o O_TARGET := base.o
obj-y := core.o sys.o interface.o fs.o power.o obj-y := core.o sys.o interface.o fs.o power.o bus.o
export-objs := core.o fs.o power.o sys.o export-objs := core.o fs.o power.o sys.o bus.o
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
extern struct device device_root; extern struct device device_root;
extern spinlock_t device_lock; extern spinlock_t device_lock;
extern int bus_add_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
extern int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent);
extern int device_make_dir(struct device * dev); extern int device_make_dir(struct device * dev);
extern void device_remove_dir(struct device * dev); extern void device_remove_dir(struct device * dev);
extern int device_bus_link(struct device * dev);
/*
* bus.c - bus driver management
*
* Copyright (c) 2002 Patrick Mochel
* 2002 Open Source Development Lab
*
*
*/
#define DEBUG 0
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include "base.h"
static LIST_HEAD(bus_driver_list);
static struct driver_dir_entry bus_dir = {
name: "bus",
mode: (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO),
};
/**
* bus_add_device - add device to bus
* @dev: device being added
*
* Add the device to its bus's list of devices.
* Create a symlink in the bus's 'devices' directory to the
* device's physical location.
* Try and bind the device to a driver.
*/
int bus_add_device(struct device * dev)
{
if (dev->bus) {
pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name);
get_bus(dev->bus);
write_lock(&dev->bus->lock);
list_add_tail(&dev->bus_list,&dev->bus->devices);
write_unlock(&dev->bus->lock);
device_bus_link(dev);
}
return 0;
}
/**
* bus_remove_device - remove device from bus
* @dev: device to be removed
*
* Remove symlink from bus's directory.
* Delete device from bus's list.
*/
void bus_remove_device(struct device * dev)
{
if (dev->bus) {
driverfs_remove_file(&dev->bus->device_dir,dev->bus_id);
write_lock(&dev->bus->lock);
list_del_init(&dev->bus_list);
write_unlock(&dev->bus->lock);
put_bus(dev->bus);
}
}
static int bus_make_dir(struct bus_type * bus)
{
int error;
bus->dir.name = bus->name;
error = device_create_dir(&bus->dir,&bus_dir);
if (!error) {
bus->device_dir.name = "devices";
device_create_dir(&bus->device_dir,&bus->dir);
bus->driver_dir.name = "drivers";
device_create_dir(&bus->driver_dir,&bus->dir);
}
return error;
}
int bus_register(struct bus_type * bus)
{
spin_lock(&device_lock);
rwlock_init(&bus->lock);
INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers);
list_add_tail(&bus->node,&bus_driver_list);
atomic_set(&bus->refcount,2);
spin_unlock(&device_lock);
pr_debug("bus type '%s' registered\n",bus->name);
/* give it some driverfs entities */
bus_make_dir(bus);
put_bus(bus);
return 0;
}
void put_bus(struct bus_type * bus)
{
if (!atomic_dec_and_lock(&bus->refcount,&device_lock))
return;
list_del_init(&bus->node);
spin_unlock(&device_lock);
/* remove driverfs entries */
driverfs_remove_dir(&bus->driver_dir);
driverfs_remove_dir(&bus->device_dir);
driverfs_remove_dir(&bus->dir);
}
static int __init bus_init(void)
{
/* make 'bus' driverfs directory */
return driverfs_create_dir(&bus_dir,NULL);
}
core_initcall(bus_init);
EXPORT_SYMBOL(bus_add_device);
EXPORT_SYMBOL(bus_remove_device);
EXPORT_SYMBOL(bus_register);
EXPORT_SYMBOL(put_bus);
...@@ -70,6 +70,8 @@ int device_register(struct device *dev) ...@@ -70,6 +70,8 @@ int device_register(struct device *dev)
if ((error = device_make_dir(dev))) if ((error = device_make_dir(dev)))
goto register_done; goto register_done;
bus_add_device(dev);
/* notify platform of device entry */ /* notify platform of device entry */
if (platform_notify) if (platform_notify)
platform_notify(dev); platform_notify(dev);
...@@ -96,15 +98,14 @@ void put_device(struct device * dev) ...@@ -96,15 +98,14 @@ void put_device(struct device * dev)
DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n", DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
dev->bus_id,dev->name); dev->bus_id,dev->name);
/* remove the driverfs directory */
device_remove_dir(dev);
/* Notify the platform of the removal, in case they /* Notify the platform of the removal, in case they
* need to do anything... * need to do anything...
*/ */
if (platform_notify_remove) if (platform_notify_remove)
platform_notify_remove(dev); platform_notify_remove(dev);
bus_remove_device(dev);
/* Tell the driver to clean up after itself. /* Tell the driver to clean up after itself.
* Note that we likely didn't allocate the device, * Note that we likely didn't allocate the device,
* so this is the driver's chance to free that up... * so this is the driver's chance to free that up...
...@@ -112,6 +113,12 @@ void put_device(struct device * dev) ...@@ -112,6 +113,12 @@ void put_device(struct device * dev)
if (dev->driver && dev->driver->remove) if (dev->driver && dev->driver->remove)
dev->driver->remove(dev,REMOVE_FREE_RESOURCES); dev->driver->remove(dev,REMOVE_FREE_RESOURCES);
/* remove the driverfs directory */
device_remove_dir(dev);
if (dev->release)
dev->release(dev);
put_device(dev->parent); put_device(dev->parent);
} }
......
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
* 2002 Open Source Development Lab * 2002 Open Source Development Lab
*/ */
#define DEBUG 0
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/limits.h>
extern struct driver_file_entry * device_default_files[]; extern struct driver_file_entry * device_default_files[];
...@@ -68,6 +71,92 @@ void device_remove_dir(struct device * dev) ...@@ -68,6 +71,92 @@ void device_remove_dir(struct device * dev)
driverfs_remove_dir(&dev->dir); driverfs_remove_dir(&dev->dir);
} }
static int get_devpath_length(struct device * dev)
{
int length = 1;
struct device * parent = dev;
/* walk up the ancestors until we hit the root.
* Add 1 to strlen for leading '/' of each level.
*/
do {
length += strlen(parent->bus_id) + 1;
parent = parent->parent;
} while (parent);
return length;
}
static void fill_devpath(struct device * dev, char * path, int length)
{
struct device * parent;
--length;
for (parent = dev; parent; parent = parent->parent) {
int cur = strlen(parent->bus_id);
/* back up enough to print this bus id with '/' */
length -= cur;
strncpy(path + length,parent->bus_id,cur);
*(path + --length) = '/';
}
pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
}
static int create_symlink(struct driver_dir_entry * parent, char * name, char * path)
{
struct driver_file_entry * entry;
entry = kmalloc(sizeof(struct driver_file_entry),GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->name = name;
entry->mode = S_IRUGO;
return driverfs_create_symlink(parent,entry,path);
}
int device_bus_link(struct device * dev)
{
char * path;
int length;
int error = 0;
if (!dev->bus)
return 0;
length = get_devpath_length(dev);
/* now add the path from the bus directory
* It should be '../../..' (one to get to the bus's directory,
* one to get to the 'bus' directory, and one to get to the root
* of the fs.)
*/
length += strlen("../../..");
if (length > PATH_MAX)
return -ENAMETOOLONG;
if (!(path = kmalloc(length,GFP_KERNEL)))
return -ENOMEM;
memset(path,0,length);
/* our relative position */
strcpy(path,"../../..");
fill_devpath(dev,path,length);
error = create_symlink(&dev->bus->device_dir,dev->bus_id,path);
kfree(path);
return error;
}
int device_create_dir(struct driver_dir_entry * dir, struct driver_dir_entry * parent)
{
INIT_LIST_HEAD(&dir->files);
dir->mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
return driverfs_create_dir(dir,parent);
}
/** /**
* device_make_dir - create a driverfs directory * device_make_dir - create a driverfs directory
* @name: name of directory * @name: name of directory
...@@ -87,23 +176,20 @@ int device_make_dir(struct device * dev) ...@@ -87,23 +176,20 @@ int device_make_dir(struct device * dev)
int error; int error;
int i; int i;
INIT_LIST_HEAD(&dev->dir.files);
dev->dir.mode = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
dev->dir.name = dev->bus_id;
if (dev->parent) if (dev->parent)
parent = &dev->parent->dir; parent = &dev->parent->dir;
dev->dir.name = dev->bus_id;
if ((error = driverfs_create_dir(&dev->dir,parent))) if ((error = device_create_dir(&dev->dir,parent)))
return error; return error;
for (i = 0; (entry = *(device_default_files + i)); i++) { for (i = 0; (entry = *(device_default_files + i)); i++) {
if ((error = device_create_file(dev,entry))) { if ((error = device_create_file(dev,entry))) {
device_remove_dir(dev); device_remove_dir(dev);
return error; break;
} }
} }
return 0; return error;
} }
EXPORT_SYMBOL(device_create_file); EXPORT_SYMBOL(device_create_file);
......
...@@ -164,6 +164,17 @@ struct device_driver pci_device_driver = { ...@@ -164,6 +164,17 @@ struct device_driver pci_device_driver = {
resume: pci_device_resume, resume: pci_device_resume,
}; };
struct bus_type pci_bus_type = {
name: "pci",
};
static int __init pci_driver_init(void)
{
return bus_register(&pci_bus_type);
}
subsys_initcall(pci_driver_init);
EXPORT_SYMBOL(pci_match_device); EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_register_driver); EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver); EXPORT_SYMBOL(pci_unregister_driver);
......
...@@ -512,6 +512,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) ...@@ -512,6 +512,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
dev0.sysdata = bus->sysdata; dev0.sysdata = bus->sysdata;
dev0.dev.parent = bus->dev; dev0.dev.parent = bus->dev;
dev0.dev.driver = &pci_device_driver; dev0.dev.driver = &pci_device_driver;
dev0.dev.bus = &pci_bus_type;
/* Go find them, Rover! */ /* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8) { for (devfn = 0; devfn < 0x100; devfn += 8) {
......
...@@ -53,11 +53,49 @@ static struct file_operations driverfs_file_operations; ...@@ -53,11 +53,49 @@ static struct file_operations driverfs_file_operations;
static struct inode_operations driverfs_dir_inode_operations; static struct inode_operations driverfs_dir_inode_operations;
static struct dentry_operations driverfs_dentry_dir_ops; static struct dentry_operations driverfs_dentry_dir_ops;
static struct dentry_operations driverfs_dentry_file_ops; static struct dentry_operations driverfs_dentry_file_ops;
static struct address_space_operations driverfs_aops;
static struct vfsmount *driverfs_mount; static struct vfsmount *driverfs_mount;
static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED; static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
static int mount_count = 0; static int mount_count = 0;
static int driverfs_readpage(struct file *file, struct page * page)
{
if (!PageUptodate(page)) {
memset(kmap(page), 0, PAGE_CACHE_SIZE);
kunmap(page);
flush_dcache_page(page);
SetPageUptodate(page);
}
unlock_page(page);
return 0;
}
static int driverfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
void *addr = kmap(page);
if (!PageUptodate(page)) {
memset(addr, 0, PAGE_CACHE_SIZE);
flush_dcache_page(page);
SetPageUptodate(page);
}
SetPageDirty(page);
return 0;
}
static int driverfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
kunmap(page);
if (pos > inode->i_size)
inode->i_size = pos;
return 0;
}
struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev) struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev)
{ {
struct inode *inode = new_inode(sb); struct inode *inode = new_inode(sb);
...@@ -70,6 +108,7 @@ struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev) ...@@ -70,6 +108,7 @@ struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev)
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_rdev = NODEV; inode->i_rdev = NODEV;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &driverfs_aops;
switch (mode & S_IFMT) { switch (mode & S_IFMT) {
default: default:
init_special_inode(inode, mode, dev); init_special_inode(inode, mode, dev);
...@@ -81,6 +120,9 @@ struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev) ...@@ -81,6 +120,9 @@ struct inode *driverfs_get_inode(struct super_block *sb, int mode, int dev)
inode->i_op = &driverfs_dir_inode_operations; inode->i_op = &driverfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations; inode->i_fop = &simple_dir_operations;
break; break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
break;
} }
} }
return inode; return inode;
...@@ -121,6 +163,24 @@ static int driverfs_create(struct inode *dir, struct dentry *dentry, int mode) ...@@ -121,6 +163,24 @@ static int driverfs_create(struct inode *dir, struct dentry *dentry, int mode)
return res; return res;
} }
static int driverfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
{
struct inode *inode;
int error = -ENOSPC;
inode = driverfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
if (inode) {
int l = strlen(symname)+1;
error = block_symlink(inode, symname, l);
if (!error) {
d_instantiate(dentry, inode);
dget(dentry);
} else
iput(inode);
}
return error;
}
static inline int driverfs_positive(struct dentry *dentry) static inline int driverfs_positive(struct dentry *dentry)
{ {
return (dentry->d_inode && !d_unhashed(dentry)); return (dentry->d_inode && !d_unhashed(dentry));
...@@ -364,10 +424,18 @@ static struct inode_operations driverfs_dir_inode_operations = { ...@@ -364,10 +424,18 @@ static struct inode_operations driverfs_dir_inode_operations = {
create: driverfs_create, create: driverfs_create,
lookup: simple_lookup, lookup: simple_lookup,
unlink: driverfs_unlink, unlink: driverfs_unlink,
symlink: driverfs_symlink,
mkdir: driverfs_mkdir, mkdir: driverfs_mkdir,
rmdir: driverfs_rmdir, rmdir: driverfs_rmdir,
}; };
static struct address_space_operations driverfs_aops = {
readpage: driverfs_readpage,
writepage: fail_writepage,
prepare_write: driverfs_prepare_write,
commit_write: driverfs_commit_write
};
static struct dentry_operations driverfs_dentry_file_ops = { static struct dentry_operations driverfs_dentry_file_ops = {
d_delete: driverfs_d_delete_file, d_delete: driverfs_d_delete_file,
}; };
...@@ -568,6 +636,52 @@ driverfs_create_file(struct driver_file_entry * entry, ...@@ -568,6 +636,52 @@ driverfs_create_file(struct driver_file_entry * entry,
return error; return error;
} }
/**
* driverfs_create_symlink - make a symlink
* @parent: directory we're creating in
* @entry: entry describing link
* @target: place we're symlinking to
*
*/
int driverfs_create_symlink(struct driver_dir_entry * parent,
struct driver_file_entry * entry,
char * target)
{
struct dentry * dentry;
struct qstr qstr;
int error = 0;
if (!entry || !parent)
return -EINVAL;
get_mount();
if (!parent->dentry) {
put_mount();
return -EINVAL;
}
down(&parent->dentry->d_inode->i_sem);
qstr.name = entry->name;
qstr.len = strlen(entry->name);
qstr.hash = full_name_hash(entry->name,qstr.len);
dentry = lookup_hash(&qstr,parent->dentry);
if (!IS_ERR(dentry)) {
dentry->d_fsdata = (void *)entry;
error = vfs_symlink(parent->dentry->d_inode,dentry,target);
if (!error) {
dentry->d_inode->u.generic_ip = (void *)entry;
entry->dentry = dentry;
entry->parent = parent;
list_add_tail(&entry->node,&parent->files);
}
} else
error = PTR_ERR(dentry);
up(&parent->dentry->d_inode->i_sem);
if (error)
put_mount();
return error;
}
/** /**
* driverfs_remove_file - exported file removal * driverfs_remove_file - exported file removal
* @dir: directory the file supposedly resides in * @dir: directory the file supposedly resides in
...@@ -641,6 +755,7 @@ void driverfs_remove_dir(struct driver_dir_entry * dir) ...@@ -641,6 +755,7 @@ void driverfs_remove_dir(struct driver_dir_entry * dir)
} }
EXPORT_SYMBOL(driverfs_create_file); EXPORT_SYMBOL(driverfs_create_file);
EXPORT_SYMBOL(driverfs_create_symlink);
EXPORT_SYMBOL(driverfs_create_dir); EXPORT_SYMBOL(driverfs_create_dir);
EXPORT_SYMBOL(driverfs_remove_file); EXPORT_SYMBOL(driverfs_remove_file);
EXPORT_SYMBOL(driverfs_remove_dir); EXPORT_SYMBOL(driverfs_remove_dir);
...@@ -391,51 +391,31 @@ int kernel_read(struct file *file, unsigned long offset, ...@@ -391,51 +391,31 @@ int kernel_read(struct file *file, unsigned long offset,
return result; return result;
} }
static int exec_mmap(void) static int exec_mmap(struct mm_struct *mm)
{ {
struct mm_struct * mm, * old_mm; struct mm_struct * old_mm, *active_mm;
/* Add it to the list of mm's */
spin_lock(&mmlist_lock);
list_add(&mm->mmlist, &init_mm.mmlist);
mmlist_nr++;
spin_unlock(&mmlist_lock);
old_mm = current->mm;
task_lock(current); task_lock(current);
if (old_mm && atomic_read(&old_mm->mm_users) == 1) { old_mm = current->mm;
mm_release(); active_mm = current->active_mm;
exit_mmap(old_mm); current->mm = mm;
task_unlock(current); current->active_mm = mm;
return 0; activate_mm(active_mm, mm);
}
task_unlock(current); task_unlock(current);
mm_release();
mm = mm_alloc(); if (old_mm) {
if (mm) { if (active_mm != old_mm) BUG();
struct mm_struct *active_mm; mmput(old_mm);
if (init_new_context(current, mm)) {
mmdrop(mm);
return -ENOMEM;
}
/* Add it to the list of mm's */
spin_lock(&mmlist_lock);
list_add(&mm->mmlist, &init_mm.mmlist);
mmlist_nr++;
spin_unlock(&mmlist_lock);
task_lock(current);
active_mm = current->active_mm;
current->mm = mm;
current->active_mm = mm;
activate_mm(active_mm, mm);
task_unlock(current);
mm_release();
if (old_mm) {
if (active_mm != old_mm) BUG();
mmput(old_mm);
return 0;
}
mmdrop(active_mm);
return 0; return 0;
} }
return -ENOMEM; mmdrop(active_mm);
return 0;
} }
/* /*
...@@ -574,7 +554,7 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -574,7 +554,7 @@ int flush_old_exec(struct linux_binprm * bprm)
/* /*
* Release all of the old mmap stuff * Release all of the old mmap stuff
*/ */
retval = exec_mmap(); retval = exec_mmap(bprm->mm);
if (retval) goto mmap_failed; if (retval) goto mmap_failed;
/* This is the point of no return */ /* This is the point of no return */
...@@ -905,17 +885,23 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs ...@@ -905,17 +885,23 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
bprm.sh_bang = 0; bprm.sh_bang = 0;
bprm.loader = 0; bprm.loader = 0;
bprm.exec = 0; bprm.exec = 0;
if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
allow_write_access(file);
fput(file);
return bprm.argc;
}
if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) { bprm.mm = mm_alloc();
allow_write_access(file); retval = -ENOMEM;
fput(file); if (!bprm.mm)
return bprm.envc; goto out_file;
}
retval = init_new_context(current, bprm.mm);
if (retval < 0)
goto out_mm;
bprm.argc = count(argv, bprm.p / sizeof(void *));
if ((retval = bprm.argc) < 0)
goto out_mm;
bprm.envc = count(envp, bprm.p / sizeof(void *));
if ((retval = bprm.envc) < 0)
goto out_mm;
retval = prepare_binprm(&bprm); retval = prepare_binprm(&bprm);
if (retval < 0) if (retval < 0)
...@@ -941,16 +927,20 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs ...@@ -941,16 +927,20 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
out: out:
/* Something went wrong, return the inode and free the argument pages*/ /* Something went wrong, return the inode and free the argument pages*/
allow_write_access(bprm.file);
if (bprm.file)
fput(bprm.file);
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
struct page * page = bprm.page[i]; struct page * page = bprm.page[i];
if (page) if (page)
__free_page(page); __free_page(page);
} }
out_mm:
mmdrop(bprm.mm);
out_file:
if (bprm.file) {
allow_write_access(bprm.file);
fput(bprm.file);
}
return retval; return retval;
} }
......
...@@ -60,5 +60,6 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) ...@@ -60,5 +60,6 @@ static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
#define pte_none(x) (!(x).pte_low) #define pte_none(x) (!(x).pte_low)
#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT))) #define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) #define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#endif /* _I386_PGTABLE_2LEVEL_H */ #endif /* _I386_PGTABLE_2LEVEL_H */
...@@ -99,4 +99,9 @@ static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) ...@@ -99,4 +99,9 @@ static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
return pte; return pte;
} }
static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
{
return __pmd(((unsigned long long)page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
}
#endif /* _I386_PGTABLE_3LEVEL_H */ #endif /* _I386_PGTABLE_3LEVEL_H */
...@@ -132,27 +132,18 @@ extern void pgtable_cache_init(void); ...@@ -132,27 +132,18 @@ extern void pgtable_cache_init(void);
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define __PAGE_KERNEL \ #define _PAGE_KERNEL \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
#define __PAGE_KERNEL_NOCACHE \
(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_PCD | _PAGE_ACCESSED) extern unsigned long __PAGE_KERNEL;
#define __PAGE_KERNEL_RO \ #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
# define MAKE_GLOBAL(x) \
({ \ #define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
pgprot_t __ret; \ #define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
\ #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
if (cpu_has_pge) \ #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
__ret = __pgprot((x) | _PAGE_GLOBAL); \
else \
__ret = __pgprot(x); \
__ret; \
})
#define PAGE_KERNEL MAKE_GLOBAL(__PAGE_KERNEL)
#define PAGE_KERNEL_RO MAKE_GLOBAL(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_NOCACHE MAKE_GLOBAL(__PAGE_KERNEL_NOCACHE)
/* /*
* The i386 can't do page protection for execute, and considers that * The i386 can't do page protection for execute, and considers that
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
struct linux_binprm{ struct linux_binprm{
char buf[BINPRM_BUF_SIZE]; char buf[BINPRM_BUF_SIZE];
struct page *page[MAX_ARG_PAGES]; struct page *page[MAX_ARG_PAGES];
struct mm_struct *mm;
unsigned long p; /* current top of mem */ unsigned long p; /* current top of mem */
int sh_bang; int sh_bang;
struct file * file; struct file * file;
......
...@@ -55,6 +55,34 @@ enum { ...@@ -55,6 +55,34 @@ enum {
struct device; struct device;
struct bus_type {
char * name;
rwlock_t lock;
atomic_t refcount;
list_t node;
list_t devices;
list_t drivers;
struct driver_dir_entry dir;
struct driver_dir_entry device_dir;
struct driver_dir_entry driver_dir;
};
extern int bus_register(struct bus_type * bus);
static inline struct bus_type * get_bus(struct bus_type * bus)
{
BUG_ON(!atomic_read(&bus->refcount));
atomic_inc(&bus->refcount);
return bus;
}
extern void put_bus(struct bus_type * bus);
struct device_driver { struct device_driver {
int (*probe) (struct device * dev); int (*probe) (struct device * dev);
int (*remove) (struct device * dev, u32 flags); int (*remove) (struct device * dev, u32 flags);
...@@ -66,6 +94,7 @@ struct device_driver { ...@@ -66,6 +94,7 @@ struct device_driver {
struct device { struct device {
struct list_head g_list; /* node in depth-first order list */ struct list_head g_list; /* node in depth-first order list */
struct list_head node; /* node in sibling list */ struct list_head node; /* node in sibling list */
struct list_head bus_list; /* node in bus's list */
struct list_head children; struct list_head children;
struct device * parent; struct device * parent;
...@@ -78,6 +107,7 @@ struct device { ...@@ -78,6 +107,7 @@ struct device {
atomic_t refcount; /* refcount to make sure the device atomic_t refcount; /* refcount to make sure the device
* persists for the right amount of time */ * persists for the right amount of time */
struct bus_type * bus; /* type of bus device is on */
struct driver_dir_entry dir; struct driver_dir_entry dir;
struct device_driver *driver; /* which driver has allocated this struct device_driver *driver; /* which driver has allocated this
...@@ -92,6 +122,8 @@ struct device { ...@@ -92,6 +122,8 @@ struct device {
being off. */ being off. */
unsigned char *saved_state; /* saved device state */ unsigned char *saved_state; /* saved device state */
void (*release)(struct device * dev);
}; };
static inline struct device * static inline struct device *
......
...@@ -56,6 +56,11 @@ extern int ...@@ -56,6 +56,11 @@ extern int
driverfs_create_file(struct driver_file_entry * entry, driverfs_create_file(struct driver_file_entry * entry,
struct driver_dir_entry * parent); struct driver_dir_entry * parent);
extern int
driverfs_create_symlink(struct driver_dir_entry * parent,
struct driver_file_entry * entry,
char * target);
extern void extern void
driverfs_remove_file(struct driver_dir_entry *, const char * name); driverfs_remove_file(struct driver_dir_entry *, const char * name);
......
...@@ -439,6 +439,7 @@ struct pci_bus { ...@@ -439,6 +439,7 @@ struct pci_bus {
extern struct list_head pci_root_buses; /* list of all known PCI buses */ extern struct list_head pci_root_buses; /* list of all known PCI buses */
extern struct list_head pci_devices; /* list of all devices */ extern struct list_head pci_devices; /* list of all devices */
extern struct bus_type pci_bus_type;
/* /*
* Error values that may be returned by PCI functions. * Error values that may be returned by PCI functions.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment