diff options
author | rn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net> | 2003-02-13 15:58:34 +0000 |
---|---|---|
committer | rn@wyvis.camb.intel-research.net <rn@wyvis.camb.intel-research.net> | 2003-02-13 15:58:34 +0000 |
commit | 87b3f71e1f82bad43200499787a5e2c1e6fbae17 (patch) | |
tree | 68628511517767c333d7715942daa16d9cca05b3 /xenolinux-2.4.16-sparse | |
parent | febde6d3526433e019a8bee635cff9dabeaf053b (diff) | |
parent | 4b929a32df3556bce2860e54c460502c751d18a4 (diff) | |
download | xen-87b3f71e1f82bad43200499787a5e2c1e6fbae17.tar.gz xen-87b3f71e1f82bad43200499787a5e2c1e6fbae17.tar.bz2 xen-87b3f71e1f82bad43200499787a5e2c1e6fbae17.zip |
bitkeeper revision 1.27 (3e4bc0aaYLPRPEot-3f6sspi3HC6Xg)
Merge with recent checkins
Diffstat (limited to 'xenolinux-2.4.16-sparse')
-rw-r--r-- | xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile | 2 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c | 827 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c | 233 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c | 27 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/drivers/block/Config.in | 51 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c | 5 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/fs/partitions/check.c | 443 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/fs/partitions/msdos.c | 642 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h | 10 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/include/linux/blk.h | 416 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/include/linux/major.h | 199 | ||||
-rw-r--r-- | xenolinux-2.4.16-sparse/init/main.c | 871 |
12 files changed, 3725 insertions, 1 deletions
diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile index 9361a01ec7..74a0c6c565 100644 --- a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile @@ -1,3 +1,3 @@ O_TARGET := blk.o -obj-y := block.o +obj-y := xl_block.o xl_block_test.o include $(TOPDIR)/Rules.make diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c new file mode 100644 index 0000000000..0416b467a7 --- /dev/null +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c @@ -0,0 +1,827 @@ +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/errno.h> + +#include <linux/fs.h> +#include <linux/hdreg.h> /* HDIO_GETGEO, et al */ +#include <linux/blkdev.h> +#include <linux/major.h> + +/* NOTE: this is drive independent, so no inclusion of ide.h */ + +#include <asm/hypervisor-ifs/block.h> +#include <asm/hypervisor-ifs/hypervisor-if.h> +#include <asm/io.h> +#include <asm/uaccess.h> /* put_user() */ + +#define MAJOR_NR XLBLK_MAJOR /* force defns in blk.h, must preceed include */ +static int xlblk_major = XLBLK_MAJOR; + +#include <linux/blk.h> /* must come after definition of MAJOR_NR!! */ + +/* instead of including linux/ide.h to pick up the definitiong of byte + * (and consequently screwing up blk.h, we'll just copy the definition */ +typedef unsigned char byte; + +void xlblk_ide_register_disk(int, unsigned long); + +#define XLBLK_MAX 2 /* very arbitrary */ +#define XLBLK_MAJOR_NAME "blk" +#define IDE_PARTN_BITS 6 /* from ide.h::PARTN_BITS */ +#define IDE_PARTN_MASK ((1<<IDE_PARTN_BITS)-1) /* from ide.h::PARTN_MASK */ +static int xlblk_blk_size[XLBLK_MAX]; +static int xlblk_blksize_size[XLBLK_MAX]; +static int xlblk_hardsect_size[XLBLK_MAX]; +static int xlblk_read_ahead[XLBLK_MAX]; +static int xlblk_max_sectors[XLBLK_MAX]; + +#define XLBLK_RX_IRQ _EVENT_BLK_RX +#define XLBLK_TX_IRQ _EVENT_BLK_TX + +typedef struct xlblk_device +{ + struct buffer_head *bh; + unsigned int tx_count; /* number of used slots in tx ring */ +} xlblk_device_t; + +xlblk_device_t xlblk_device; + +/* USE_REQUEST_QUEUE = 1 use (multiple) request queues + * = 0 don't use IO request queue + */ +#define USE_REQUEST_QUEUE 1 + +#define XLBLK_DEBUG 0 +#define XLBLK_DEBUG_IOCTL 0 + +/* + * disk management + */ + +xen_disk_info_t xen_disk_info; + +/* some declarations */ +void hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + int mode); + + +/* ------------------------------------------------------------------------ + */ + +static int xenolinux_block_open(struct inode *inode, struct file *filep) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_open\n"); } + return 0; +} + +static int xenolinux_block_release(struct inode *inode, struct file *filep) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_release\n"); } + return 0; +} + +static int xenolinux_block_ioctl(struct inode *inode, struct file *filep, + unsigned command, unsigned long argument) +{ + int minor_dev; + + if (XLBLK_DEBUG_IOCTL) + { + printk (KERN_ALERT "xenolinux_block_ioctl\n"); + } + + /* check permissions */ + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (!inode) return -EINVAL; + minor_dev = MINOR(inode->i_rdev); + if (minor_dev >= XLBLK_MAX) return -ENODEV; + + if (XLBLK_DEBUG_IOCTL) + { + printk (KERN_ALERT + " command: 0x%x, argument: 0x%lx, minor: 0x%x\n", + command, (long) argument, minor_dev); + } + + switch (command) + { + case BLKGETSIZE : + { + if (XLBLK_DEBUG_IOCTL) + { + printk (KERN_ALERT + " BLKGETSIZE: %x %lx\n", BLKGETSIZE, + (long) xen_disk_info.disks[0].capacity); + } + return put_user(xen_disk_info.disks[0].capacity, + (unsigned long *) argument); + } + case BLKRRPART : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " BLKRRPART: %x\n", BLKRRPART); } + break; + } + case BLKSSZGET : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " BLKSSZGET: %x 0x%x\n", BLKSSZGET, + xlblk_hardsect_size[minor_dev]); } + return xlblk_hardsect_size[minor_dev]; + } + case HDIO_GETGEO : + { + struct hd_geometry *geo = (struct hd_geometry *)argument; + + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " HDIO_GETGEO: %x\n", HDIO_GETGEO); } + + if (!argument) return -EINVAL; + /* + if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x20b, (unsigned short *) &geo->cylinders)) return -EFAULT; + */ + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned short *) &geo->cylinders)) return -EFAULT; + + return 0; + } + case HDIO_GETGEO_BIG : + { + struct hd_big_geometry *geo = (struct hd_big_geometry *) argument; + + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " HDIO_GETGEO_BIG: %x\n", HDIO_GETGEO_BIG); } + + if (!argument) return -EINVAL; + /* + if (put_user(0x80, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x20b, (unsigned int *) &geo->cylinders)) return -EFAULT; + */ + if (put_user(0x00, (unsigned long *) &geo->start)) return -EFAULT; + if (put_user(0xff, (byte *)&geo->heads)) return -EFAULT; + if (put_user(0x3f, (byte *)&geo->sectors)) return -EFAULT; + if (put_user(0x106, (unsigned int *) &geo->cylinders)) return -EFAULT; + + return 0; + } + default : + { + if (XLBLK_DEBUG_IOCTL) { + printk (KERN_ALERT " eh? unknown ioctl\n"); } + break; + } + } + + return 0; +} + +static int xenolinux_block_check(kdev_t dev) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_check\n"); } + return 0; +} + +static int xenolinux_block_revalidate(kdev_t dev) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xenolinux_block_revalidate\n"); } + return 0; +} + +/* + * hypervisor_request + * + * request block io + * + * id: for guest use only. + * operation: XEN_BLOCK_READ, XEN_BLOCK_WRITE or XEN_BLOCK_PROBE + * buffer: buffer to read/write into. this should be a + * virtual address in the guest os. + * block_number: block to read + * block_size: size of each block + * device: ide/hda is 768 or 0x300 + * mode: XEN_BLOCK_SYNC or XEN_BLOCK_ASYNC. async requests + * will queue until a sync request is issued. + */ + +void hypervisor_request(void * id, + int operation, + char * buffer, + unsigned long block_number, + unsigned short block_size, + kdev_t device, + int mode) +{ + blk_ring_t *blk_ring = start_info.blk_ring; + int position; + void *buffer_pa, *buffer_ma; + kdev_t phys_device = (kdev_t) 0; + unsigned long sector_number = 0; + +#if 0 + printk(KERN_ALERT "[%x]", id); + printk (KERN_ALERT + "xlblk_req: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n", + id, operation, buffer, block_number, block_size, device); +#endif + + /* XXX SMH: now need to convert guest virtual address to machine address */ + buffer_pa = (void *)virt_to_phys((unsigned long)buffer); + buffer_ma = (void *)phys_to_machine((unsigned long)buffer_pa); + +#if 0 + printk(KERN_ALERT "va %p => pa %p => ma %p\n", buffer, buffer_pa, buffer_ma); +#endif + + if (operation == XEN_BLOCK_PROBE) + { + phys_device = (kdev_t) 0; + sector_number = 0; + } + else if (operation == XEN_BLOCK_READ || operation == XEN_BLOCK_WRITE) + { + /* + * map logial major device to the physical device number + * + * XLBLK_MAJOR -> IDE0_MAJOR (123 -> 3) + */ + if (MAJOR(device) == XLBLK_MAJOR) + { + phys_device = MKDEV(IDE0_MAJOR, 0); + } + else + { + printk (KERN_ALERT + "error: xl_block::hypervisor_request: unknown device [0x%x]\n", + device); + BUG(); + } + + /* + * compute real buffer location on disk + * (from ll_rw_block.c::submit_bh) + */ + { + int idx = 0; + + struct gendisk *gd = (struct gendisk *) xen_disk_info.disks[idx].gendisk; + unsigned int minor = MINOR(device); + + sector_number = block_number /* * block_size >> 9 */; + + if (gd != NULL) /* if we have a partition table... */ + { + sector_number += gd->part[minor & IDE_PARTN_MASK].start_sect; + } + } + } + + /* + * CHECK TO SEE IF THERE IS SPACE IN THE RING + */ + if (BLK_TX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons) + { + printk (KERN_ALERT "hypervisor_request: tx_cons: %d, tx_prod:%d", + blk_ring->tx_cons, blk_ring->tx_prod); + } + + /* fill out a communications ring structure + and then trap into the hypervisor */ + position = blk_ring->tx_prod; + blk_ring->tx_ring[position].id = id; + blk_ring->tx_ring[position].priority = mode; + blk_ring->tx_ring[position].operation = operation; + blk_ring->tx_ring[position].buffer = buffer_ma; + blk_ring->tx_ring[position].block_number = block_number; + blk_ring->tx_ring[position].block_size = block_size; + blk_ring->tx_ring[position].device = phys_device; + blk_ring->tx_ring[position].sector_number = sector_number; + + blk_ring->tx_prod = BLK_TX_RING_INC(blk_ring->tx_prod); + + if (mode == XEN_BLOCK_SYNC) + { + /* trap into hypervisor */ + HYPERVISOR_block_io_op(); + } + else if (mode == XEN_BLOCK_ASYNC) + { + /* for now, do nothing. the request will go in the ring and + the next sync request will trigger the hypervisor to act */ + } + else + { + /* ummm, unknown mode. */ + BUG(); + } + + return; +} + + +/* + * do_xlblk_request + * + * read a block; request is in a request queue + * + * TO DO: should probably release the io_request_lock and then re-acquire + * (see LDD p. 338) + */ + +static void do_xlblk_request (request_queue_t *rq) +{ + struct request *req; + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT "xlblk.c::do_xlblk_request for '%s'\n", DEVICE_NAME); + } + + while (!QUEUE_EMPTY) + { + struct buffer_head *bh; + unsigned long offset; + unsigned long length; + int rw; + + req = CURRENT; + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT + "do_xlblk_request %p: cmd %i, sec %lx, (%li) bh:%p\n", + req, req->cmd, req->sector, + req->current_nr_sectors, req->bh); + } + + /* is there space in the tx ring for this request? + * if the ring is full, then leave the request in the queue + * + * THIS IS A BIT BOGUS SINCE XEN COULD BE UPDATING TX_CONS + * AT THE SAME TIME + */ + { + blk_ring_t *blk_ring = start_info.blk_ring; + + if (BLK_RX_RING_INC(blk_ring->tx_prod) == blk_ring->tx_cons) + { + printk (KERN_ALERT "OOPS, TX LOOKS FULL cons: %d prod: %d\n", + blk_ring->tx_cons, blk_ring->tx_prod); + break; + } + } + + req->errors = 0; + blkdev_dequeue_request(req); + + bh = req->bh; + + while (bh) + { + + offset = bh->b_rsector << 9; + length = bh->b_size; + + rw = req->cmd; + if (rw == READA) rw= READ; + if ((rw != READ) && (rw != WRITE)) + { + printk (KERN_ALERT + "XenoLinux Virtual Block Device: bad command: %d\n", rw); + BUG(); + } + + /* + if (XLBLK_DEBUG) + { + printk (KERN_ALERT "xlblk.c::do_xlblk_request\n"); + printk (KERN_ALERT " b_blocknr: 0x%lx %ld\n", + bh->b_blocknr, bh->b_blocknr); + printk (KERN_ALERT " b_size: 0x%x %d\n", bh->b_size, bh->b_size); + printk (KERN_ALERT " b_dev: 0x%x %d\n", bh->b_dev, bh->b_dev); + printk (KERN_ALERT " b_rsector: 0x%lx %ld\n", + bh->b_rsector, bh->b_rsector); + } + */ + + hypervisor_request (req, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, + bh->b_data, bh->b_rsector, bh->b_size, + bh->b_dev, XEN_BLOCK_SYNC); + + bh = bh->b_reqnext; + } + } + + return; +} + +/* + * xenolinux_block_request + * + * read a block without using a request queue + */ + +static int xenolinux_block_request(request_queue_t *rq, + int rw, + struct buffer_head *bh) +{ + unsigned int minor; + unsigned long offset; + unsigned long length; + + if (XLBLK_DEBUG) { + printk (KERN_ALERT "xlblk.c::xenolinux_block_request: %lx %d %lx\n", + (unsigned long) rq, rw, (unsigned long) bh); } + /* + printk (KERN_ALERT "xlblk.c::xlblk_request: op:%d bh:%p sect:%lu sz:%u\n", + rw, bh, bh->b_rsector, bh->b_size); + */ + + minor = MINOR(bh->b_rdev); + + offset = bh->b_rsector << 9; + length = bh->b_size; + + if (rw == READA) rw= READ; + if ((rw != READ) && (rw != WRITE)) + { + printk (KERN_ALERT + "XenoLinux Virtual Block Device: bad command: %d\n", rw); + goto fail; + } + + hypervisor_request (bh, rw == READ ? XEN_BLOCK_READ : XEN_BLOCK_WRITE, + bh->b_data, bh->b_rsector, bh->b_size, + bh->b_dev, XEN_BLOCK_SYNC); + + return 0; + + fail: + return 0; +} + +static struct block_device_operations xenolinux_block_fops = +{ + open: xenolinux_block_open, + release: xenolinux_block_release, + ioctl: xenolinux_block_ioctl, + check_media_change: xenolinux_block_check, + revalidate: xenolinux_block_revalidate, +}; + +static void xlblk_rx_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + xlblk_device_t *dev = (xlblk_device_t *)dev_id; + blk_ring_t *blk_ring = start_info.blk_ring; + struct buffer_head *bh; + struct request *req; + int loop; + + for (loop = blk_ring->rx_cons; + loop != blk_ring->rx_prod; + loop = BLK_RX_RING_INC(loop)) + { + blk_ring_entry_t *bret = &blk_ring->rx_ring[loop]; + void *buffer_pa, *buffer_va; + + buffer_pa = machine_to_phys((unsigned long)bret->buffer); + buffer_va = phys_to_virt((unsigned long)buffer_pa); + +#if 0 + printk(KERN_ALERT "xlblk_rx_int: buffer ma %p => pa %p => va %p\n", + bret->buffer, buffer_pa, buffer_va); + + + if (XLBLK_DEBUG) + { + printk (KERN_ALERT + "xlblock::xlblk_rx_int [%s]\n", + (bret->operation == XEN_BLOCK_READ) ? "read" : "write"); + printk (KERN_ALERT + " vbuf: %lx, pbuf: %lx, blockno: %lx, size: %x, device %x\n", + (unsigned long) buffer_va, (unsigned long) bret->buffer, + bret->block_number, bret->block_size, bret->device); + printk (KERN_ALERT " bret: %p bh: %p\n", bret, bret->id); + } + + /* + printk (KERN_ALERT + "xlblk_rx: id:%p op:%d, bf:%p, blk:%lu, sz:%u, dev:%x\n", + bret->id, bret->operation, bret->buffer, bret->block_number, + bret->block_size, bret->device); + */ +#endif + + if (USE_REQUEST_QUEUE) + { + req = (struct request *)bret->id; + printk(KERN_ALERT "|%x|", req); + + if (!end_that_request_first(req, 1, "NAME")) + { + blkdev_dequeue_request(req); + + /* should be end_that_request_last(req) + to wake up waiting processes (with complete) */ + blkdev_release_request(req); + } + + /* + if (XLBLK_DEBUG) + { + int temp; + printk(KERN_ALERT + "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n", + vbuffer, bret->block_number, bret->block_size, bret->device, + bh->b_end_io); + + for (temp = 0; temp < bret->block_size; temp++) + { + if (temp % 16 == 0) printk ("[%4x] ", temp); + else if (temp % 4 == 0) printk (" "); + printk ("%02x", + vbuffer[temp] & 255); + if ((temp + 1) % 16 == 0) printk ("\n"); + } + printk ("\n\n"); + } + */ + +#ifdef BOGUS + req = (struct request *)bret->id; + while ((bh = req->bh) != NULL) + { + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh,1); + } + blkdev_release_request(req); +#endif /* BOGUS */ + } + else + { + bh = (struct buffer_head *)bret->id; + bh->b_end_io(bh,1); + + /* + if (XLBLK_DEBUG) + { + int temp; +#if 0 + printk(KERN_ALERT + "buff: 0x%p, blkno: 0x%lx, size: 0x%x, device 0x%x [%p]\n", + vbuffer, bret->block_number, bret->block_size, bret->device, + bh->b_end_io); +#endif + + for (temp = 0; temp < bret->block_size; temp++) + { + if (temp % 16 == 0) printk ("[%4x] ", temp); + else if (temp % 4 == 0) printk (" "); + printk ("%02x", + vbuffer[temp] & 255); + if ((temp + 1) % 16 == 0) printk ("\n"); + } + printk ("\n\n"); + } + */ + } + } + + blk_ring->rx_cons = loop; +} + +static void xlblk_tx_int(int irq, void *dev_id, struct pt_regs *ptregs) +{ + if (XLBLK_DEBUG) { + printk (KERN_ALERT "--- xlblock::xlblk_tx_int\n"); } +} + +int __init xlblk_init(void) +{ + blk_ring_t *blk_ring = start_info.blk_ring; + int loop, error, result; + + /* + * initialize memory rings to communicate with hypervisor + */ + + if ( blk_ring == NULL ) return -ENOMEM; + + blk_ring->tx_prod = blk_ring->tx_cons = 0; + blk_ring->rx_prod = blk_ring->rx_cons = 0; + blk_ring->tx_ring = NULL; + blk_ring->rx_ring = NULL; + + blk_ring->tx_ring = kmalloc(BLK_TX_RING_SIZE * sizeof(blk_ring_entry_t), + GFP_KERNEL); + blk_ring->rx_ring = kmalloc(BLK_RX_RING_SIZE * sizeof(blk_ring_entry_t), + GFP_KERNEL); + + if ((blk_ring->tx_ring == NULL) || + (blk_ring->rx_ring == NULL)) + { + printk (KERN_ALERT + "error, could not allocate ring memory for block device\n"); + error = -ENOBUFS; + goto fail; + } + + /* + * setup soft interrupts to communicate with hypervisor + */ + + error = request_irq(XLBLK_RX_IRQ, xlblk_rx_int, 0, "xlblk-rx", + &xlblk_device); + if (error) + { + printk(KERN_ALERT "Could not allocate receive interrupt\n"); + goto fail; + } + + error = request_irq(XLBLK_TX_IRQ, xlblk_tx_int, 0, "xlblk-tx", + &xlblk_device); + if (error) + { + printk(KERN_ALERT "Could not allocate transmit interrupt\n"); + free_irq(XLBLK_RX_IRQ, &xlblk_device); + goto fail; + } + + /* + * get information about physical drives + * + */ + { + /* NOTE: this should only occur in domain 0 */ + memset (&xen_disk_info, 0, sizeof(xen_disk_info)); + xen_disk_info.count = 0; + + hypervisor_request(NULL, XEN_BLOCK_PROBE, (char *) &xen_disk_info, + 0, 0, (kdev_t) 0, XEN_BLOCK_SYNC); + + { + int loop; + for (loop = 0; loop < xen_disk_info.count; loop++) + { + printk (KERN_ALERT " %2d: type: %d, capacity: %ld\n", + loop, xen_disk_info.disks[loop].type, + xen_disk_info.disks[loop].capacity); + } + } + } + + /* + * initialize device driver + */ + + SET_MODULE_OWNER(&xenolinux_block_fops); + + result = register_blkdev(xlblk_major, "block", &xenolinux_block_fops); + if (result < 0) + { + printk (KERN_ALERT "xenolinux block: can't get major %d\n", xlblk_major); + return result; + } + + /* initialize global arrays in drivers/block/ll_rw_block.c */ + blk_size[xlblk_major] = xlblk_blk_size; + blksize_size[xlblk_major] = xlblk_blksize_size; + hardsect_size[xlblk_major] = xlblk_hardsect_size; + read_ahead[xlblk_major] = xlblk_read_ahead; + max_sectors[xlblk_major] = xlblk_max_sectors; + for (loop = 0; loop < XLBLK_MAX; loop++) + { + xlblk_blk_size[loop] = xen_disk_info.disks[0].capacity; + xlblk_blksize_size[loop] = 512; + xlblk_hardsect_size[loop] = 512; + xlblk_read_ahead[loop] = 8; + xlblk_max_sectors[loop] = 128; + } + + if (USE_REQUEST_QUEUE) + { + /* NEED TO MODIFY THIS TO HANDLE MULTIPLE QUEUES + * also, should replace do_xlblk_request with blk.h::DEVICE_REQUEST + */ + blk_init_queue(BLK_DEFAULT_QUEUE(xlblk_major), do_xlblk_request); + blk_queue_headactive(BLK_DEFAULT_QUEUE(xlblk_major), 0); + } + else + { + /* we don't use __make_request in ll_rw_blk */ + blk_queue_make_request(BLK_DEFAULT_QUEUE(xlblk_major), + xenolinux_block_request); + } + xlblk_ide_register_disk(0, xen_disk_info.disks[0].capacity); + + /* + * completion + */ + printk(KERN_ALERT + "XenoLinux Virtual Block Device Driver installed [device: %d]\n", + xlblk_major); + return 0; + + fail: + if (blk_ring->tx_ring) kfree(blk_ring->tx_ring); + if (blk_ring->rx_ring) kfree(blk_ring->rx_ring); + return error; +} + +void xlblk_ide_register_disk(int idx, unsigned long capacity) +{ + int units; + int minors; + struct gendisk *gd; + + /* plagarized from ide-probe.c::init_gendisk */ + + units = 2; /* from ide.h::MAX_DRIVES */ + + minors = units * (1<<IDE_PARTN_BITS); + gd = kmalloc (sizeof(struct gendisk), GFP_KERNEL); + gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL); + gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); + memset(gd->part, 0, minors * sizeof(struct hd_struct)); + + gd->major = xlblk_major; /* our major device number */ + gd->major_name = XLBLK_MAJOR_NAME; /* treated special in genhd.c */ + gd->minor_shift = IDE_PARTN_BITS; /* num bits for partitions */ + gd->max_p = 1<<IDE_PARTN_BITS; /* 1 + max partitions / drive */ + gd->nr_real = units; /* current num real drives */ + gd->real_devices= NULL; /* ptr to internal data (was: hwif) */ + gd->next = NULL; /* linked list of major devs */ + gd->fops = &xenolinux_block_fops; /* file operations */ + gd->de_arr = kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL); + gd->flags = kmalloc (sizeof *gd->flags * units, GFP_KERNEL); + if (gd->de_arr) memset (gd->de_arr, 0, sizeof *gd->de_arr * units); + if (gd->flags) memset (gd->flags, 0, sizeof *gd->flags * units); + add_gendisk(gd); + + xen_disk_info.disks[idx].gendisk = gd; + + /* default disk size is just a big number. in the future, we + need a message to probe the devices to determine the actual size */ + register_disk(gd, MKDEV(xlblk_major, 0), 1<<IDE_PARTN_BITS, + &xenolinux_block_fops, capacity); + + return; +} + +static void __exit xlblk_cleanup(void) +{ + /* CHANGE FOR MULTIQUEUE */ + blk_cleanup_queue(BLK_DEFAULT_QUEUE(xlblk_major)); + + /* clean up global arrays */ + read_ahead[xlblk_major] = 0; + if (blk_size[xlblk_major]) kfree(blk_size[xlblk_major]); + blk_size[xlblk_major] = NULL; + if (blksize_size[xlblk_major]) kfree(blksize_size[xlblk_major]); + blksize_size[xlblk_major] = NULL; + if (hardsect_size[xlblk_major]) kfree(hardsect_size[xlblk_major]); + hardsect_size[xlblk_major] = NULL; + + /* + * + * TODO: FOR EACH GENDISK, FREE + * + */ + + if (unregister_blkdev(xlblk_major, "block")) + { + printk(KERN_ALERT + "XenoLinux Virtual Block Device Driver uninstalled with errors\n"); + } + else + { + printk(KERN_ALERT "XenoLinux Virtual Block Device Driver uninstalled\n"); + } + + return; +} + + +#ifdef MODULE +module_init(xlblk_init); +module_exit(xlblk_cleanup); +#endif diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c new file mode 100644 index 0000000000..cab6d9a330 --- /dev/null +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c @@ -0,0 +1,233 @@ +/****************************************************************************** + * xenolinux_block_test.c + * + */ +#define EXPORT_SYMTAB + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/sched.h> +#include <asm/uaccess.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/errno.h> + +#include <asm/hypervisor-ifs/block.h> +#include <asm/hypervisor-ifs/hypervisor-if.h> + +/******************************************************************/ + +static struct proc_dir_entry *bdt; +static blk_ring_entry_t meta; +static char * data; + +static int proc_read_bdt(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + switch (meta.operation) + { + case XEN_BLOCK_READ : + case XEN_BLOCK_WRITE : + { + return proc_dump_block(page, start, off, count, eof, data); + } + case XEN_BLOCK_DEBUG : + { + return proc_dump_debug(page, start, off, count, eof, data); + } + default : + { + printk(KERN_ALERT + "block device test error: unknown operation [%c]\n", + meta.operation); + return -EINVAL; + } + } +} + +int proc_dump_debug(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char header[100]; + char dump[1024]; + + sprintf (header, "Block Device Test: Debug Dump\n\n"); + + sprintf (dump, "%s\n", meta.buffer); + + if (data) + { + kfree(data); + } + + strncpy (page, dump, count); + return strlen(page); +} + +int proc_dump_block(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + char header[100]; + char dump[1024]; + char temp[100]; + int loop; + + sprintf (header, "Block Device Test\n\n%s blk num: %ld 0x%lx; size: %d 0x%x; device: 0x%x\n", + meta.operation == XEN_BLOCK_WRITE ? "write" : "read", + meta.block_number, meta.block_number, + meta.block_size, meta.block_size, + meta.device); + + sprintf (dump, "%s", header); + + if (meta.buffer) + { + for (loop = 0; loop < 100; loop++) + { + int i = meta.buffer[loop]; + + if (loop % 8 == 0) + { + sprintf (temp, "[%2d] ", loop); + strcat(dump, temp); + } + else if (loop % 2 == 0) + { + strcat(dump, " "); + } + + sprintf (temp, " 0x%02x", i & 255); + strcat(dump, temp); + if ((loop + 1) % 8 == 0) + { + strcat(dump, "\n"); + } + } + strcat(dump, "\n\n"); + } + + if (data) + { + kfree(data); + } + + strncpy (page, dump, count); + return strlen(page); +} + +int proc_write_bdt(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char *local = kmalloc((count + 1) * sizeof(char), GFP_KERNEL); + char opcode; + int block_number = 0; + int block_size = 0; + int device = 0; + int mode; + + if (copy_from_user(local, buffer, count)) + { + return -EFAULT; + } + local[count] = '\0'; + + sscanf(local, "%c %i %i %i", + &opcode, &block_number, &block_size, &device); + + if (opcode == 'r' || opcode == 'R') + { + meta.operation = XEN_BLOCK_READ; + } + else if (opcode == 'w' || opcode == 'W') + { + meta.operation = XEN_BLOCK_WRITE; + } + else if (opcode == 'd' || opcode == 'D') + { + meta.operation = XEN_BLOCK_DEBUG; + block_size = 10000; + } + else + { + printk(KERN_ALERT + "block device test error: unknown opcode [%c]\n", opcode); + return -EINVAL; + } + + if (opcode == 'r' || opcode == 'w' || + opcode == 'd' || opcode == 'D') + { + mode = XEN_BLOCK_SYNC; + } + else /* (opcode == 'R' || opcode == 'W') */ + { + mode = XEN_BLOCK_ASYNC; + } + + if (data) + { + kfree(data); + } + data = kmalloc(block_size * sizeof(char), GFP_KERNEL); + if (data == NULL) + { + kfree(local); + return -ENOMEM; + } + + meta.block_number = block_number; + meta.block_size = block_size; + meta.device = device; + meta.buffer = data; + + /* submit request */ + hypervisor_request(0, meta.operation, meta.buffer, + meta.block_number, meta.block_size, + meta.device, mode); + + kfree(local); + return count; +} + + +static int __init init_module(void) +{ + int return_value = 0; + + /* create proc entry */ + bdt = create_proc_entry("bdt", 0644, NULL); + if (bdt == NULL) + { + return_value = -ENOMEM; + goto error; + } + bdt->data = NULL; + bdt->read_proc = proc_read_bdt; + bdt->write_proc = proc_write_bdt; + bdt->owner = THIS_MODULE; + + memset(&meta, 0, sizeof(meta)); + + /* success */ + printk(KERN_ALERT "XenoLinux Block Device Test installed\n"); + return 0; + + error: + return return_value; +} + +static void __exit cleanup_module(void) +{ + if (data) + { + kfree(data); + } + printk(KERN_ALERT "XenoLinux Block Device Test uninstalled\n"); +} + +module_init(init_module); +module_exit(cleanup_module); diff --git a/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c new file mode 100644 index 0000000000..97d4a65b78 --- /dev/null +++ b/xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c @@ -0,0 +1,27 @@ +/* + * domain 0 block driver interface + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> + +static int __init init_module(void) +{ + request_module("xl_block"); + printk("Successfully installed domain 0 block interface\n"); + + + return 0; +} + +static void __exit cleanup_module(void) +{ + printk("Successfully de-installed domain-0 block interface\n"); + return 0; +} + +module_init(init_module); +module_exit(cleanup_module); diff --git a/xenolinux-2.4.16-sparse/drivers/block/Config.in b/xenolinux-2.4.16-sparse/drivers/block/Config.in new file mode 100644 index 0000000000..716774fe74 --- /dev/null +++ b/xenolinux-2.4.16-sparse/drivers/block/Config.in @@ -0,0 +1,51 @@ +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Block devices' + +tristate 'Normal PC floppy disk support' CONFIG_BLK_DEV_FD +if [ "$CONFIG_AMIGA" = "y" ]; then + tristate 'Amiga floppy support' CONFIG_AMIGA_FLOPPY +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY +fi +if [ "$CONFIG_MAC" = "y" ]; then + dep_bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP $CONFIG_EXPERIMENTAL +fi +if [ "$CONFIG_MCA" = "y" ]; then + tristate 'PS/2 ESDI hard disk support' CONFIG_BLK_DEV_PS2 +fi +if [ "$CONFIG_ZORRO" = "y" ]; then + tristate 'Amiga Zorro II ramdisk support' CONFIG_AMIGA_Z2RAM +fi +if [ "$CONFIG_ATARI" = "y" ]; then + tristate 'Atari ACSI support' CONFIG_ATARI_ACSI + if [ "$CONFIG_ATARI_ACSI" != "n" ]; then + comment 'Some devices (e.g. CD jukebox) support multiple LUNs' + bool ' Probe all LUNs on each ACSI device' CONFIG_ACSI_MULTI_LUN + tristate ' Atari SLM laser printer support' CONFIG_ATARI_SLM + fi +fi +dep_tristate 'XT hard disk support' CONFIG_BLK_DEV_XD $CONFIG_ISA +dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARPORT +if [ "$CONFIG_PARIDE" = "y" -o "$CONFIG_PARIDE" = "m" ]; then + source drivers/block/paride/Config.in +fi +dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI +dep_tristate 'Compaq Smart Array 5xxx support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI +dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI + +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET + +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then + int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 +fi +dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM + +bool 'XenoLinux virtual block device support' CONFIG_XENOLINUX_BLOCK + +endmenu diff --git a/xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c b/xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c index a9e973d05f..c6d5c9625b 100644 --- a/xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c +++ b/xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c @@ -1227,6 +1227,11 @@ int __init blk_dev_init(void) #ifdef CONFIG_SUN_JSFLASH jsfd_init(); #endif + +#ifdef CONFIG_XENOLINUX_BLOCK + xlblk_init(); +#endif + return 0; }; diff --git a/xenolinux-2.4.16-sparse/fs/partitions/check.c b/xenolinux-2.4.16-sparse/fs/partitions/check.c new file mode 100644 index 0000000000..e564544ec6 --- /dev/null +++ b/xenolinux-2.4.16-sparse/fs/partitions/check.c @@ -0,0 +1,443 @@ +/* + * Code extracted from drivers/block/genhd.c + * Copyright (C) 1991-1998 Linus Torvalds + * Re-organised Feb 1998 Russell King + * + * We now have independent partition support from the + * block drivers, which allows all the partition code to + * be grouped in one location, and it to be mostly self + * contained. + * + * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} + */ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/genhd.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/blk.h> +#include <linux/init.h> +#include <linux/raid/md.h> + +#include "check.h" + +#include "acorn.h" +#include "amiga.h" +#include "atari.h" +#include "ldm.h" +#include "mac.h" +#include "msdos.h" +#include "osf.h" +#include "sgi.h" +#include "sun.h" +#include "ibm.h" +#include "ultrix.h" + +extern int *blk_size[]; + +#define CHECK_DEBUG 0 + +int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ + +static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = { +#ifdef CONFIG_ACORN_PARTITION + acorn_partition, +#endif +#ifdef CONFIG_LDM_PARTITION + ldm_partition, /* this must come before msdos */ +#endif +#ifdef CONFIG_MSDOS_PARTITION + msdos_partition, +#endif +#ifdef CONFIG_OSF_PARTITION + osf_partition, +#endif +#ifdef CONFIG_SUN_PARTITION + sun_partition, +#endif +#ifdef CONFIG_AMIGA_PARTITION + amiga_partition, +#endif +#ifdef CONFIG_ATARI_PARTITION + atari_partition, +#endif +#ifdef CONFIG_MAC_PARTITION + mac_partition, +#endif +#ifdef CONFIG_SGI_PARTITION + sgi_partition, +#endif +#ifdef CONFIG_ULTRIX_PARTITION + ultrix_partition, +#endif +#ifdef CONFIG_IBM_PARTITION + ibm_partition, +#endif + NULL +}; + +/* + * This is ucking fugly but its probably the best thing for 2.4.x + * Take it as a clear reminder than we should put the device name + * generation in the object kdev_t points to in 2.5. + */ + +#ifdef CONFIG_ARCH_S390 +int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +EXPORT_SYMBOL(genhd_dasd_name); +#endif + +/* + * disk_name() is used by partition check code and the md driver. + * It formats the devicename of the indicated disk into + * the supplied buffer (of size at least 32), and returns + * a pointer to that same buffer (for convenience). + */ + +char *disk_name (struct gendisk *hd, int minor, char *buf) +{ + const char *maj = hd->major_name; + unsigned int unit = (minor >> hd->minor_shift); + unsigned int part = (minor & ((1 << hd->minor_shift) -1 )); + + if ((unit < hd->nr_real) && hd->part[minor].de) { + int pos; + + pos = devfs_generate_path (hd->part[minor].de, buf, 64); + if (pos >= 0) + return buf + pos; + } + +#ifdef CONFIG_ARCH_S390 + if (genhd_dasd_name + && genhd_dasd_name (buf, unit, part, hd) == 0) + return buf; +#endif + /* + * IDE devices use multiple major numbers, but the drives + * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. + * This requires special handling here. + */ + switch (hd->major) { + case IDE9_MAJOR: + unit += 2; + case IDE8_MAJOR: + unit += 2; + case IDE7_MAJOR: + unit += 2; + case IDE6_MAJOR: + unit += 2; + case IDE5_MAJOR: + unit += 2; + case IDE4_MAJOR: + unit += 2; + case IDE3_MAJOR: + unit += 2; + case IDE2_MAJOR: + unit += 2; + case IDE1_MAJOR: + unit += 2; + case IDE0_MAJOR: + maj = "hd"; + break; + case MD_MAJOR: + sprintf(buf, "%s%d", maj, unit); + return buf; + } + if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) { + unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16; + if (unit+'a' > 'z') { + unit -= 26; + sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26); + if (part) + sprintf(buf + 4, "%d", part); + return buf; + } + } + if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) { + int ctlr = hd->major - COMPAQ_SMART2_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) { + int ctlr = hd->major - COMPAQ_CISS_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) { + int ctlr = hd->major - DAC960_MAJOR; + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, unit); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part); + return buf; + } + if (hd->major == ATARAID_MAJOR) { + int disk = minor >> hd->minor_shift; + int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) + sprintf(buf, "%s/d%d", maj, disk); + else + sprintf(buf, "%s/d%dp%d", maj, disk, part); + return buf; + } + if (part) + sprintf(buf, "%s%c%d", maj, unit+'a', part); + else + sprintf(buf, "%s%c", maj, unit+'a'); + return buf; +} + +/* + * Add a partitions details to the devices partition description. + */ +void add_gd_partition(struct gendisk *hd, int minor, int start, int size) +{ +#ifndef CONFIG_DEVFS_FS + char buf[40]; +#endif + + hd->part[minor].start_sect = start; + hd->part[minor].nr_sects = size; +#ifdef CONFIG_DEVFS_FS + printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); +#else + if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) || + (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)) + printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); + else + printk(" %s", disk_name(hd, minor, buf)); +#endif +} + +static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor) +{ + devfs_handle_t de = NULL; + static int first_time = 1; + unsigned long first_sector; + struct block_device *bdev; + char buf[64]; + int i; + + if (CHECK_DEBUG) printk (KERN_ALERT "check.c::check_partition\n"); + + if (first_time) + printk(KERN_INFO "Partition check:\n"); + first_time = 0; + first_sector = hd->part[MINOR(dev)].start_sect; + + /* + * This is a kludge to allow the partition check to be + * skipped for specific drives (e.g. IDE CD-ROM drives) + */ + if ((int)first_sector == -1) { + hd->part[MINOR(dev)].start_sect = 0; + return; + } + + if (hd->de_arr) + de = hd->de_arr[MINOR(dev) >> hd->minor_shift]; + i = devfs_generate_path (de, buf, sizeof buf); + if (i >= 0) + printk(KERN_INFO " /dev/%s:", buf + i); + else + printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf)); + bdev = bdget(kdev_t_to_nr(dev)); + bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9; + bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev)); + for (i = 0; check_part[i]; i++) { + int res; + res = check_part[i](hd, bdev, first_sector, first_part_minor); + if (res) { + if (res < 0 && warn_no_part) + printk(" unable to read partition table\n"); + goto setup_devfs; + } + } + + printk(" unknown partition table\n"); +setup_devfs: + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + bdput(bdev); + i = first_part_minor - 1; + devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); +} + +#ifdef CONFIG_DEVFS_FS +static void devfs_register_partition (struct gendisk *dev, int minor, int part) +{ + int devnum = minor >> dev->minor_shift; + devfs_handle_t dir; + unsigned int devfs_flags = DEVFS_FL_DEFAULT; + char devname[16]; + + if (dev->part[minor + part].de) return; + dir = devfs_get_parent (dev->part[minor].de); + if (!dir) return; + if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) ) + devfs_flags |= DEVFS_FL_REMOVABLE; + sprintf (devname, "part%d", part); + dev->part[minor + part].de = + devfs_register (dir, devname, devfs_flags, + dev->major, minor + part, + S_IFBLK | S_IRUSR | S_IWUSR, + dev->fops, NULL); +} + +static struct unique_numspace disc_numspace = UNIQUE_NUMBERSPACE_INITIALISER; + +static void devfs_register_disc (struct gendisk *dev, int minor) +{ + int pos = 0; + int devnum = minor >> dev->minor_shift; + devfs_handle_t dir, slave; + unsigned int devfs_flags = DEVFS_FL_DEFAULT; + char dirname[64], symlink[16]; + static devfs_handle_t devfs_handle; + + if (dev->part[minor].de) return; + if ( dev->flags && (dev->flags[devnum] & GENHD_FL_REMOVABLE) ) + devfs_flags |= DEVFS_FL_REMOVABLE; + if (dev->de_arr) { + dir = dev->de_arr[devnum]; + if (!dir) /* Aware driver wants to block disc management */ + return; + pos = devfs_generate_path (dir, dirname + 3, sizeof dirname-3); + if (pos < 0) return; + strncpy (dirname + pos, "../", 3); + } + else { + /* Unaware driver: construct "real" directory */ + sprintf (dirname, "../%s/disc%d", dev->major_name, devnum); + dir = devfs_mk_dir (NULL, dirname + 3, NULL); + } + if (!devfs_handle) + devfs_handle = devfs_mk_dir (NULL, "discs", NULL); + dev->part[minor].number = devfs_alloc_unique_number (&disc_numspace); + sprintf (symlink, "disc%d", dev->part[minor].number); + devfs_mk_symlink (devfs_handle, symlink, DEVFS_FL_DEFAULT, + dirname + pos, &slave, NULL); + dev->part[minor].de = + devfs_register (dir, "disc", devfs_flags, dev->major, minor, + S_IFBLK | S_IRUSR | S_IWUSR, dev->fops, NULL); + devfs_auto_unregister (dev->part[minor].de, slave); + if (!dev->de_arr) + devfs_auto_unregister (slave, dir); +} +#endif /* CONFIG_DEVFS_FS */ + +void devfs_register_partitions (struct gendisk *dev, int minor, int unregister) +{ +#ifdef CONFIG_DEVFS_FS + int part; + + if (!unregister) + devfs_register_disc (dev, minor); + for (part = 1; part < dev->max_p; part++) { + if ( unregister || (dev->part[part + minor].nr_sects < 1) ) { + devfs_unregister (dev->part[part + minor].de); + dev->part[part + minor].de = NULL; + continue; + } + devfs_register_partition (dev, minor, part); + } + if (unregister) { + devfs_unregister (dev->part[minor].de); + dev->part[minor].de = NULL; + devfs_dealloc_unique_number (&disc_numspace, + dev->part[minor].number); + } +#endif /* CONFIG_DEVFS_FS */ +} + +/* + * This function will re-read the partition tables for a given device, + * and set things back up again. There are some important caveats, + * however. You must ensure that no one is using the device, and no one + * can start using the device while this function is being executed. + * + * Much of the cleanup from the old partition tables should have already been + * done + */ + +void register_disk(struct gendisk *gdev, kdev_t dev, unsigned minors, + struct block_device_operations *ops, long size) +{ + if (CHECK_DEBUG) + { + if (gdev != NULL) + printk (KERN_ALERT + "check.c::register_disk gdev:%p dev:%d min:%u ops:%p sz:%ld\n", + gdev, dev, minors, ops, size); + } + + if (!gdev) + return; + + grok_partitions(gdev, MINOR(dev)>>gdev->minor_shift, minors, size); +} + +void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size) +{ + int i; + int first_minor = drive << dev->minor_shift; + int end_minor = first_minor + dev->max_p; + + if (CHECK_DEBUG) printk (KERN_ALERT "check.c::grok_partitions\n"); + + if(!dev->sizes) + blk_size[dev->major] = NULL; + + dev->part[first_minor].nr_sects = size; + /* No such device or no minors to use for partitions */ + if (!size || minors == 1) + return; + + if (dev->sizes) { + dev->sizes[first_minor] = size >> (BLOCK_SIZE_BITS - 9); + for (i = first_minor + 1; i < end_minor; i++) + dev->sizes[i] = 0; + } + blk_size[dev->major] = dev->sizes; + check_partition(dev, MKDEV(dev->major, first_minor), 1 + first_minor); + + /* + * We need to set the sizes array before we will be able to access + * any of the partitions on this device. + */ + if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ + for (i = first_minor; i < end_minor; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); + } +} + +unsigned char *read_dev_sector(struct block_device *bdev, unsigned long n, Sector *p) +{ + struct address_space *mapping = bdev->bd_inode->i_mapping; + int sect = PAGE_CACHE_SIZE / 512; + struct page *page; + + page = read_cache_page(mapping, n/sect, + (filler_t *)mapping->a_ops->readpage, NULL); + if (!IS_ERR(page)) { + wait_on_page(page); + if (!Page_Uptodate(page)) + goto fail; + if (PageError(page)) + goto fail; + p->v = page; + return (unsigned char *)page_address(page) + 512 * (n % sect); +fail: + page_cache_release(page); + } + p->v = NULL; + return NULL; +} diff --git a/xenolinux-2.4.16-sparse/fs/partitions/msdos.c b/xenolinux-2.4.16-sparse/fs/partitions/msdos.c new file mode 100644 index 0000000000..34a086024e --- /dev/null +++ b/xenolinux-2.4.16-sparse/fs/partitions/msdos.c @@ -0,0 +1,642 @@ +/* + * fs/partitions/msdos.c + * + * Code extracted from drivers/block/genhd.c + * Copyright (C) 1991-1998 Linus Torvalds + * + * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug + * in the early extended-partition checks and added DM partitions + * + * Support for DiskManager v6.0x added by Mark Lord, + * with information provided by OnTrack. This now works for linux fdisk + * and LILO, as well as loadlin and bootln. Note that disks other than + * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). + * + * More flexible handling of extended partitions - aeb, 950831 + * + * Check partition table on IDE disks for common CHS translations + * + * Re-organised Feb 1998 Russell King + */ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/genhd.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/blk.h> + +#ifdef CONFIG_BLK_DEV_IDE +#include <linux/ide.h> /* IDE xlate */ +#endif /* CONFIG_BLK_DEV_IDE */ + +#define MSDOS_DEBUG 0 + +#include <asm/system.h> + +#include "check.h" +#include "msdos.h" + +#if CONFIG_BLK_DEV_MD +extern void md_autodetect_dev(kdev_t dev); +#endif + +/* + * Many architectures don't like unaligned accesses, which is + * frequently the case with the nr_sects and start_sect partition + * table entries. + */ +#include <asm/unaligned.h> + +#define SYS_IND(p) (get_unaligned(&p->sys_ind)) +#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \ + get_unaligned(&p->nr_sects); \ + le32_to_cpu(__a); \ + }) + +#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \ + get_unaligned(&p->start_sect); \ + le32_to_cpu(__a); \ + }) + +static inline int is_extended_partition(struct partition *p) +{ + return (SYS_IND(p) == DOS_EXTENDED_PARTITION || + SYS_IND(p) == WIN98_EXTENDED_PARTITION || + SYS_IND(p) == LINUX_EXTENDED_PARTITION); +} + +/* + * partition_name() formats the short partition name into the supplied + * buffer, and returns a pointer to that buffer. + * Used by several partition types which makes conditional inclusion messy, + * use __attribute__ ((unused)) instead. + */ +static char __attribute__ ((unused)) + *partition_name (struct gendisk *hd, int minor, char *buf) +{ +#ifdef CONFIG_DEVFS_FS + sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1))); + return buf; +#else + return disk_name(hd, minor, buf); +#endif +} + +#define MSDOS_LABEL_MAGIC1 0x55 +#define MSDOS_LABEL_MAGIC2 0xAA + +static inline int +msdos_magic_present(unsigned char *p) +{ + return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); +} + +/* + * Create devices for each logical partition in an extended partition. + * The logical partitions form a linked list, with each entry being + * a partition table with two entries. The first entry + * is the real data partition (with a start relative to the partition + * table start). The second is a pointer to the next logical partition + * (with a start relative to the entire extended partition). + * We do not create a Linux partition for the partition tables, but + * only for the actual data partitions. + */ + +static void extended_partition(struct gendisk *hd, struct block_device *bdev, + int minor, unsigned long first_size, int *current_minor) +{ + struct partition *p; + Sector sect; + unsigned char *data; + unsigned long first_sector, this_sector, this_size; + int mask = (1 << hd->minor_shift) - 1; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; + int loopct = 0; /* number of links followed + without finding a data partition */ + int i; + + this_sector = first_sector = hd->part[minor].start_sect; + this_size = first_size; + + while (1) { + if (++loopct > 100) + return; + if ((*current_minor & mask) == 0) + return; + data = read_dev_sector(bdev, this_sector, §); + if (!data) + return; + + if (!msdos_magic_present(data + 510)) + goto done; + + p = (struct partition *) (data + 0x1be); + + /* + * Usually, the first entry is the real data partition, + * the 2nd entry is the next extended partition, or empty, + * and the 3rd and 4th entries are unused. + * However, DRDOS sometimes has the extended partition as + * the first entry (when the data partition is empty), + * and OS/2 seems to use all four entries. + */ + + /* + * First process the data partition(s) + */ + for (i=0; i<4; i++, p++) { + unsigned long offs, size, next; + if (!NR_SECTS(p) || is_extended_partition(p)) + continue; + + /* Check the 3rd and 4th entries - + these sometimes contain random garbage */ + offs = START_SECT(p)*sector_size; + size = NR_SECTS(p)*sector_size; + next = this_sector + offs; + if (i >= 2) { + if (offs + size > this_size) + continue; + if (next < first_sector) + continue; + if (next + size > first_sector + first_size) + continue; + } + + add_gd_partition(hd, *current_minor, next, size); +#if CONFIG_BLK_DEV_MD + if (SYS_IND(p) == LINUX_RAID_PARTITION) { + md_autodetect_dev(MKDEV(hd->major,*current_minor)); + } +#endif + + (*current_minor)++; + loopct = 0; + if ((*current_minor & mask) == 0) + goto done; + } + /* + * Next, process the (first) extended partition, if present. + * (So far, there seems to be no reason to make + * extended_partition() recursive and allow a tree + * of extended partitions.) + * It should be a link to the next logical partition. + * Create a minor for this just long enough to get the next + * partition table. The minor will be reused for the next + * data partition. + */ + p -= 4; + for (i=0; i<4; i++, p++) + if (NR_SECTS(p) && is_extended_partition(p)) + break; + if (i == 4) + goto done; /* nothing left to do */ + + this_sector = first_sector + START_SECT(p) * sector_size; + this_size = NR_SECTS(p) * sector_size; + minor = *current_minor; + put_dev_sector(sect); + } +done: + put_dev_sector(sect); +} + +/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also + indicates linux swap. Be careful before believing this is Solaris. */ + +static void +solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ + +#ifdef CONFIG_SOLARIS_X86_PARTITION + long offset = hd->part[minor].start_sect; + Sector sect; + struct solaris_x86_vtoc *v; + struct solaris_x86_slice *s; + int mask = (1 << hd->minor_shift) - 1; + int i; + char buf[40]; + + v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); + if (!v) + return; + if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { + put_dev_sector(sect); + return; + } + printk(" %s: <solaris:", partition_name(hd, minor, buf)); + if (le32_to_cpu(v->v_version) != 1) { + printk(" cannot handle version %d vtoc>\n", + le32_to_cpu(v->v_version)); + put_dev_sector(sect); + return; + } + for (i=0; i<SOLARIS_X86_NUMSLICE; i++) { + if ((*current_minor & mask) == 0) + break; + s = &v->v_slice[i]; + + if (s->s_size == 0) + continue; + printk(" [s%d]", i); + /* solaris partitions are relative to current MS-DOS + * one but add_gd_partition starts relative to sector + * zero of the disk. Therefore, must add the offset + * of the current partition */ + add_gd_partition(hd, *current_minor, + le32_to_cpu(s->s_start)+offset, + le32_to_cpu(s->s_size)); + (*current_minor)++; + } + put_dev_sector(sect); + printk(" >\n"); +#endif +} + +#ifdef CONFIG_BSD_DISKLABEL +static void +check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p, + int minor, int *current_minor) +{ + struct hd_struct *lin_p; + /* check relative position of partitions. */ + for (lin_p = hd->part + 1 + minor; + lin_p - hd->part - minor < *current_minor; lin_p++) { + /* no relationship -> try again */ + if (lin_p->start_sect + lin_p->nr_sects <= le32_to_cpu(bsd_p->p_offset) || + lin_p->start_sect >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) + continue; + /* equal -> no need to add */ + if (lin_p->start_sect == le32_to_cpu(bsd_p->p_offset) && + lin_p->nr_sects == le32_to_cpu(bsd_p->p_size)) + return; + /* bsd living within dos partition */ + if (lin_p->start_sect <= le32_to_cpu(bsd_p->p_offset) && lin_p->start_sect + + lin_p->nr_sects >= le32_to_cpu(bsd_p->p_offset) + le32_to_cpu(bsd_p->p_size)) { +#ifdef DEBUG_BSD_DISKLABEL + printk("w: %d %ld+%ld,%d+%d", + lin_p - hd->part, + lin_p->start_sect, lin_p->nr_sects, + le32_to_cpu(bsd_p->p_offset), + le32_to_cpu(bsd_p->p_size)); +#endif + break; + } + /* ouch: bsd and linux overlap. Don't even try for that partition */ +#ifdef DEBUG_BSD_DISKLABEL + printk("???: %d %ld+%ld,%d+%d", + lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects, + le32_to_cpu(bsd_p->p_offset), le32_to_cpu(bsd_p->p_size)); +#endif + printk("???"); + return; + } /* if the bsd partition is not currently known to linux, we end + * up here + */ + add_gd_partition(hd, *current_minor, le32_to_cpu(bsd_p->p_offset), + le32_to_cpu(bsd_p->p_size)); + (*current_minor)++; +} + +/* + * Create devices for BSD partitions listed in a disklabel, under a + * dos-like partition. See extended_partition() for more information. + */ +static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor, char *name, int max_partitions) +{ + long offset = hd->part[minor].start_sect; + Sector sect; + struct bsd_disklabel *l; + struct bsd_partition *p; + int mask = (1 << hd->minor_shift) - 1; + char buf[40]; + + l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §); + if (!l) + return; + if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { + put_dev_sector(sect); + return; + } + printk(" %s: <%s", partition_name(hd, minor, buf), name); + + if (le16_to_cpu(l->d_npartitions) < max_partitions) + max_partitions = le16_to_cpu(l->d_npartitions); + for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { + if ((*current_minor & mask) == 0) + break; + if (p->p_fstype == BSD_FS_UNUSED) + continue; + check_and_add_bsd_partition(hd, p, minor, current_minor); + } + put_dev_sector(sect); + printk(" >\n"); +} +#endif + +static void bsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "bsd", + BSD_MAXPARTITIONS); +#endif +} + +static void netbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, "netbsd", + BSD_MAXPARTITIONS); +#endif +} + +static void openbsd_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_BSD_DISKLABEL + do_bsd_partition(hd, bdev, minor, current_minor, + "openbsd", OPENBSD_MAXPARTITIONS); +#endif +} + +/* + * Create devices for Unixware partitions listed in a disklabel, under a + * dos-like partition. See extended_partition() for more information. + */ +static void unixware_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_UNIXWARE_DISKLABEL + long offset = hd->part[minor].start_sect; + Sector sect; + struct unixware_disklabel *l; + struct unixware_slice *p; + int mask = (1 << hd->minor_shift) - 1; + char buf[40]; + + l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, §); + if (!l) + return; + if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || + le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { + put_dev_sector(sect); + return; + } + printk(" %s: <unixware:", partition_name(hd, minor, buf)); + p = &l->vtoc.v_slice[1]; + /* I omit the 0th slice as it is the same as whole disk. */ + while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { + if ((*current_minor & mask) == 0) + break; + + if (p->s_label != UNIXWARE_FS_UNUSED) { + add_gd_partition(hd, *current_minor, START_SECT(p), + NR_SECTS(p)); + (*current_minor)++; + } + p++; + } + put_dev_sector(sect); + printk(" >\n"); +#endif +} + +/* + * Minix 2.0.0/2.0.2 subpartition support. + * Anand Krishnamurthy <anandk@wiproge.med.ge.com> + * Rajeev V. Pillai <rajeevvp@yahoo.com> + */ +static void minix_partition(struct gendisk *hd, struct block_device *bdev, + int minor, int *current_minor) +{ +#ifdef CONFIG_MINIX_SUBPARTITION + long offset = hd->part[minor].start_sect; + Sector sect; + unsigned char *data; + struct partition *p; + int mask = (1 << hd->minor_shift) - 1; + int i; + char buf[40]; + + data = read_dev_sector(bdev, offset, §); + if (!data) + return; + + p = (struct partition *)(data + 0x1be); + + /* The first sector of a Minix partition can have either + * a secondary MBR describing its subpartitions, or + * the normal boot sector. */ + if (msdos_magic_present (data + 510) && + SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ + + printk(" %s: <minix:", partition_name(hd, minor, buf)); + for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { + if ((*current_minor & mask) == 0) + break; + /* add each partition in use */ + if (SYS_IND(p) == MINIX_PARTITION) { + add_gd_partition(hd, *current_minor, + START_SECT(p), NR_SECTS(p)); + (*current_minor)++; + } + } + printk(" >\n"); + } + put_dev_sector(sect); +#endif /* CONFIG_MINIX_SUBPARTITION */ +} + +static struct { + unsigned char id; + void (*parse)(struct gendisk *, struct block_device *, int, int *); +} subtypes[] = { + {BSD_PARTITION, bsd_partition}, + {NETBSD_PARTITION, netbsd_partition}, + {OPENBSD_PARTITION, openbsd_partition}, + {MINIX_PARTITION, minix_partition}, + {UNIXWARE_PARTITION, unixware_partition}, + {SOLARIS_X86_PARTITION, solaris_x86_partition}, + {0, NULL}, +}; +/* + * Look for various forms of IDE disk geometry translation + */ +static int handle_ide_mess(struct block_device *bdev) +{ +#ifdef CONFIG_BLK_DEV_IDE + Sector sect; + unsigned char *data; + kdev_t dev = to_kdev_t(bdev->bd_dev); + unsigned int sig; + int heads = 0; + struct partition *p; + int i; + + if (MSDOS_DEBUG) + printk (KERN_ALERT "handle_ide_mess ------------\n"); + + /* + * The i386 partition handling programs very often + * make partitions end on cylinder boundaries. + * There is no need to do so, and Linux fdisk doesnt always + * do this, and Windows NT on Alpha doesnt do this either, + * but still, this helps to guess #heads. + */ + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + if (!msdos_magic_present(data + 510)) { + put_dev_sector(sect); + return 0; + } + sig = le16_to_cpu(*(unsigned short *)(data + 2)); + p = (struct partition *) (data + 0x1be); + for (i = 0; i < 4; i++) { + struct partition *q = &p[i]; + if (NR_SECTS(q)) { + if ((q->sector & 63) == 1 && + (q->end_sector & 63) == 63) + heads = q->end_head + 1; + break; + } + } + if (SYS_IND(p) == EZD_PARTITION) { + /* + * Accesses to sector 0 must go to sector 1 instead. + */ + if (ide_xlate_1024(dev, -1, heads, " [EZD]")) + goto reread; + } else if (SYS_IND(p) == DM6_PARTITION) { + + /* + * Everything on the disk is offset by 63 sectors, + * including a "new" MBR with its own partition table. + */ + if (ide_xlate_1024(dev, 1, heads, " [DM6:DDO]")) + goto reread; + } else if (sig <= 0x1ae && + data[sig] == 0xAA && data[sig+1] == 0x55 && + (data[sig+2] & 1)) { + /* DM6 signature in MBR, courtesy of OnTrack */ + (void) ide_xlate_1024 (dev, 0, heads, " [DM6:MBR]"); + } else if (SYS_IND(p) == DM6_AUX1PARTITION || + SYS_IND(p) == DM6_AUX3PARTITION) { + /* + * DM6 on other than the first (boot) drive + */ + (void) ide_xlate_1024(dev, 0, heads, " [DM6:AUX]"); + } else { + (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); + } + put_dev_sector(sect); + + if (MSDOS_DEBUG) + printk (KERN_ALERT "handle_ide_mess -------- %d\n", heads); + return 1; + +reread: + put_dev_sector(sect); + /* Flush the cache */ + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); +#endif /* CONFIG_BLK_DEV_IDE */ + return 1; +} + +int msdos_partition(struct gendisk *hd, struct block_device *bdev, + unsigned long first_sector, int first_part_minor) +{ + int i, minor = first_part_minor; + Sector sect; + struct partition *p; + unsigned char *data; + int mask = (1 << hd->minor_shift) - 1; + int sector_size = get_hardsect_size(to_kdev_t(bdev->bd_dev)) / 512; + int current_minor = first_part_minor; + int err; + + if (MSDOS_DEBUG) printk (KERN_ALERT "msdos.c::msdos_partition\n"); + err = handle_ide_mess(bdev); + if (err <= 0) + return err; + data = read_dev_sector(bdev, 0, §); + if (!data) + return -1; + if (!msdos_magic_present(data + 510)) { + put_dev_sector(sect); + return 0; + } + p = (struct partition *) (data + 0x1be); + + /* + * Look for partitions in two passes: + * First find the primary and DOS-type extended partitions. + * On the second pass look inside *BSD, Unixware and Solaris partitions. + */ + + current_minor += 4; + for (i=1 ; i<=4 ; minor++,i++,p++) { + if (!NR_SECTS(p)) + continue; + add_gd_partition(hd, minor, + first_sector+START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size); +#if CONFIG_BLK_DEV_MD + if (SYS_IND(p) == LINUX_RAID_PARTITION) { + md_autodetect_dev(MKDEV(hd->major,minor)); + } +#endif + if (is_extended_partition(p)) { + unsigned long size = hd->part[minor].nr_sects; + printk(" <"); + /* prevent someone doing mkfs or mkswap on an + extended partition, but leave room for LILO */ + if (size > 2) + hd->part[minor].nr_sects = 2; + extended_partition(hd, bdev, minor, size, ¤t_minor); + printk(" >"); + } + } + + /* + * Check for old-style Disk Manager partition table + */ + if (msdos_magic_present(data + 0xfc)) { + p = (struct partition *) (0x1be + data); + for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & mask) == 0) + break; + if (!(START_SECT(p) && NR_SECTS(p))) + continue; + add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); + } + } + printk("\n"); + + /* second pass - output for each on a separate line */ + minor -= 4; + p = (struct partition *) (0x1be + data); + for (i=1 ; i<=4 ; minor++,i++,p++) { + unsigned char id = SYS_IND(p); + int n; + + if (!NR_SECTS(p)) + continue; + + for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) + ; + + if (subtypes[n].parse) + subtypes[n].parse(hd, bdev, minor, ¤t_minor); + } + put_dev_sector(sect); + return 1; +} diff --git a/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h b/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h index 8269718ec8..df25598730 100644 --- a/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h +++ b/xenolinux-2.4.16-sparse/include/asm-xeno/hypervisor.h @@ -258,6 +258,16 @@ static inline int HYPERVISOR_network_op(void *network_op) return ret; } +static inline int HYPERVISOR_block_io_op(void) +{ + int ret; + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret) : "0" (__HYPERVISOR_block_io_op) ); + + return ret; +} + static inline int HYPERVISOR_set_debugreg(int reg, unsigned long value) { int ret; diff --git a/xenolinux-2.4.16-sparse/include/linux/blk.h b/xenolinux-2.4.16-sparse/include/linux/blk.h new file mode 100644 index 0000000000..12eb99ff16 --- /dev/null +++ b/xenolinux-2.4.16-sparse/include/linux/blk.h @@ -0,0 +1,416 @@ +#ifndef _BLK_H +#define _BLK_H + +#include <linux/blkdev.h> +#include <linux/locks.h> +#include <linux/config.h> +#include <linux/spinlock.h> + +/* + * Spinlock for protecting the request queue which + * is mucked around with in interrupts on potentially + * multiple CPU's.. + */ +extern spinlock_t io_request_lock; + +/* + * Initialization functions. + */ +extern int isp16_init(void); +extern int cdu31a_init(void); +extern int acsi_init(void); +extern int mcd_init(void); +extern int mcdx_init(void); +extern int sbpcd_init(void); +extern int aztcd_init(void); +extern int sony535_init(void); +extern int gscd_init(void); +extern int cm206_init(void); +extern int optcd_init(void); +extern int sjcd_init(void); +extern int cdi_init(void); +extern int hd_init(void); +extern int ide_init(void); +extern int xd_init(void); +extern int mfm_init(void); +extern int loop_init(void); +extern int md_init(void); +extern int ap_init(void); +extern int ddv_init(void); +extern int z2_init(void); +extern int swim3_init(void); +extern int swimiop_init(void); +extern int amiga_floppy_init(void); +extern int atari_floppy_init(void); +extern int ez_init(void); +extern int bpcd_init(void); +extern int ps2esdi_init(void); +extern int jsfd_init(void); +extern int viodasd_init(void); +extern int viocd_init(void); +extern int xlblk_init(void); + +#if defined(CONFIG_ARCH_S390) +extern int dasd_init(void); +extern int xpram_init(void); +extern int tapeblock_init(void); +#endif /* CONFIG_ARCH_S390 */ + +extern void set_device_ro(kdev_t dev,int flag); +void add_blkdev_randomness(int major); + +extern int floppy_init(void); +extern void rd_load(void); +extern int rd_init(void); +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ + +#ifdef CONFIG_BLK_DEV_INITRD + +#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */ + +extern unsigned long initrd_start,initrd_end; +extern int mount_initrd; /* zero if initrd should not be mounted */ +extern int initrd_below_start_ok; /* 1 if it is not an error if initrd_start < memory_start */ +void initrd_init(void); + +#endif + + +/* + * end_request() and friends. Must be called with the request queue spinlock + * acquired. All functions called within end_request() _must_be_ atomic. + * + * Several drivers define their own end_request and call + * end_that_request_first() and end_that_request_last() + * for parts of the original function. This prevents + * code duplication in drivers. + */ + +static inline void blkdev_dequeue_request(struct request * req) +{ + list_del(&req->queue); +} + +int end_that_request_first(struct request *req, int uptodate, char *name); +void end_that_request_last(struct request *req); + +#if defined(MAJOR_NR) || defined(IDE_DRIVER) + +#undef DEVICE_ON +#undef DEVICE_OFF + +/* + * Add entries as needed. + */ + +#ifdef IDE_DRIVER + +#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) +#define DEVICE_NAME "ide" + +#elif (MAJOR_NR == RAMDISK_MAJOR) + +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_NO_RANDOM + +#elif (MAJOR_NR == Z2RAM_MAJOR) + +/* Zorro II Ram */ +#define DEVICE_NAME "Z2RAM" +#define DEVICE_REQUEST do_z2_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == FLOPPY_MAJOR) + +static void floppy_off(unsigned int nr); + +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 )) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == HD_MAJOR) + +/* Hard disk: timeout is 6 seconds. */ +#define DEVICE_NAME "hard disk" +#define DEVICE_INTR do_hd +#define TIMEOUT_VALUE (6*HZ) +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)>>6) + +#elif (SCSI_DISK_MAJOR(MAJOR_NR)) + +#define DEVICE_NAME "scsidisk" +#define TIMEOUT_VALUE (2*HZ) +#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4)) + +/* Kludge to use the same number for both char and block major numbers */ +#elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) + +#define DEVICE_NAME "Multiple devices driver" +#define DEVICE_REQUEST do_md_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == SCSI_TAPE_MAJOR) + +#define DEVICE_NAME "scsitape" +#define DEVICE_INTR do_st +#define DEVICE_NR(device) (MINOR(device) & 0x7f) + +#elif (MAJOR_NR == OSST_MAJOR) + +#define DEVICE_NAME "onstream" +#define DEVICE_INTR do_osst +#define DEVICE_NR(device) (MINOR(device) & 0x7f) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SCSI_CDROM_MAJOR) + +#define DEVICE_NAME "CD-ROM" +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == XT_DISK_MAJOR) + +#define DEVICE_NAME "xt disk" +#define DEVICE_REQUEST do_xd_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == PS2ESDI_MAJOR) + +#define DEVICE_NAME "PS/2 ESDI" +#define DEVICE_REQUEST do_ps2esdi_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == CDU31A_CDROM_MAJOR) + +#define DEVICE_NAME "CDU31A" +#define DEVICE_REQUEST do_cdu31a_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE)) + +#define DEVICE_NAME "ACSI" +#define DEVICE_INTR do_acsi +#define DEVICE_REQUEST do_acsi_request +#define DEVICE_NR(device) (MINOR(device) >> 4) + +#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR) + +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcd */ +#define DEVICE_REQUEST do_mcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR) + +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcdx */ +#define DEVICE_REQUEST do_mcdx_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #1" +#define DEVICE_REQUEST do_sbpcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #2" +#define DEVICE_REQUEST do_sbpcd2_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #3" +#define DEVICE_REQUEST do_sbpcd3_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM controller #4" +#define DEVICE_REQUEST do_sbpcd4_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == AZTECH_CDROM_MAJOR) + +#define DEVICE_NAME "Aztech CD-ROM" +#define DEVICE_REQUEST do_aztcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == CDU535_CDROM_MAJOR) + +#define DEVICE_NAME "SONY-CDU535" +#define DEVICE_INTR do_cdu535 +#define DEVICE_REQUEST do_cdu535_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR) + +#define DEVICE_NAME "Goldstar R420" +#define DEVICE_REQUEST do_gscd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == CM206_CDROM_MAJOR) +#define DEVICE_NAME "Philips/LMS CD-ROM cm206" +#define DEVICE_REQUEST do_cm206_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == OPTICS_CDROM_MAJOR) + +#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM" +#define DEVICE_REQUEST do_optcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == SANYO_CDROM_MAJOR) + +#define DEVICE_NAME "Sanyo H94A CD-ROM" +#define DEVICE_REQUEST do_sjcd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == APBLOCK_MAJOR) + +#define DEVICE_NAME "apblock" +#define DEVICE_REQUEST ap_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == DDV_MAJOR) + +#define DEVICE_NAME "ddv" +#define DEVICE_REQUEST ddv_request +#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS) + +#elif (MAJOR_NR == MFM_ACORN_MAJOR) + +#define DEVICE_NAME "mfm disk" +#define DEVICE_INTR do_mfm +#define DEVICE_REQUEST do_mfm_request +#define DEVICE_NR(device) (MINOR(device) >> 6) + +#elif (MAJOR_NR == NBD_MAJOR) + +#define DEVICE_NAME "nbd" +#define DEVICE_REQUEST do_nbd_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == MDISK_MAJOR) + +#define DEVICE_NAME "mdisk" +#define DEVICE_REQUEST mdisk_request +#define DEVICE_NR(device) (MINOR(device)) + +#elif (MAJOR_NR == DASD_MAJOR) + +#define DEVICE_NAME "dasd" +#define DEVICE_REQUEST do_dasd_request +#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS) + +#elif (MAJOR_NR == I2O_MAJOR) + +#define DEVICE_NAME "I2O block" +#define DEVICE_REQUEST i2ob_request +#define DEVICE_NR(device) (MINOR(device)>>4) + +#elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) + +#define DEVICE_NAME "ida" +#define TIMEOUT_VALUE (25*HZ) +#define DEVICE_REQUEST do_ida_request +#define DEVICE_NR(device) (MINOR(device) >> 4) + +#elif (MAJOR_NR == XLBLK_MAJOR) + +#define DEVICE_NAME "blk" +#define DEVICE_REQUEST do_xlblk_request +/* #define DEVICE_INTR */ +#define DEVICE_NR(device) (MINOR(device)) + +#endif /* MAJOR_NR == whatever */ + +/* provide DEVICE_xxx defaults, if not explicitly defined + * above in the MAJOR_NR==xxx if-elif tree */ +#ifndef DEVICE_ON +#define DEVICE_ON(device) do {} while (0) +#endif +#ifndef DEVICE_OFF +#define DEVICE_OFF(device) do {} while (0) +#endif + +#if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR) +#if !defined(IDE_DRIVER) + +#ifndef CURRENT +#define CURRENT blkdev_entry_next_request(&blk_dev[MAJOR_NR].request_queue.queue_head) +#endif +#ifndef QUEUE_EMPTY +#define QUEUE_EMPTY list_empty(&blk_dev[MAJOR_NR].request_queue.queue_head) +#endif + +#ifndef DEVICE_NAME +#define DEVICE_NAME "unknown" +#endif + +#define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev) + +#ifdef DEVICE_INTR +static void (*DEVICE_INTR)(void) = NULL; +#endif + +#define SET_INTR(x) (DEVICE_INTR = (x)) + +#ifdef DEVICE_REQUEST +static void (DEVICE_REQUEST)(request_queue_t *); +#endif + +#ifdef DEVICE_INTR +#define CLEAR_INTR SET_INTR(NULL) +#else +#define CLEAR_INTR +#endif + +#define INIT_REQUEST \ + if (QUEUE_EMPTY) {\ + CLEAR_INTR; \ + return; \ + } \ + if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!buffer_locked(CURRENT->bh)) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif /* !defined(IDE_DRIVER) */ + + +#ifndef LOCAL_END_REQUEST /* If we have our own end_request, we do not want to include this mess */ + +#if ! SCSI_BLK_MAJOR(MAJOR_NR) && (MAJOR_NR != COMPAQ_SMART2_MAJOR) + +static inline void end_request(int uptodate) { + struct request *req = CURRENT; + + if (end_that_request_first(req, uptodate, DEVICE_NAME)) + return; + +#ifndef DEVICE_NO_RANDOM + add_blkdev_randomness(MAJOR(req->rq_dev)); +#endif + DEVICE_OFF(req->rq_dev); + blkdev_dequeue_request(req); + end_that_request_last(req); +} + +#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */ +#endif /* LOCAL_END_REQUEST */ + +#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */ +#endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ + +#endif /* _BLK_H */ diff --git a/xenolinux-2.4.16-sparse/include/linux/major.h b/xenolinux-2.4.16-sparse/include/linux/major.h new file mode 100644 index 0000000000..820bf68dc7 --- /dev/null +++ b/xenolinux-2.4.16-sparse/include/linux/major.h @@ -0,0 +1,199 @@ +#ifndef _LINUX_MAJOR_H +#define _LINUX_MAJOR_H + +/* + * This file has definitions for major device numbers. + * For the device number assignments, see Documentation/devices.txt. + */ + +/* limits */ + +/* + * Important: Don't change this to 256. Major number 255 is and must be + * reserved for future expansion into a larger dev_t space. + */ +#define MAX_CHRDEV 255 +#define MAX_BLKDEV 255 + +#define UNNAMED_MAJOR 0 +#define MEM_MAJOR 1 +#define RAMDISK_MAJOR 1 +#define FLOPPY_MAJOR 2 +#define PTY_MASTER_MAJOR 2 +#define IDE0_MAJOR 3 +#define PTY_SLAVE_MAJOR 3 +#define HD_MAJOR IDE0_MAJOR +#define TTY_MAJOR 4 +#define TTYAUX_MAJOR 5 +#define LP_MAJOR 6 +#define VCS_MAJOR 7 +#define LOOP_MAJOR 7 +#define SCSI_DISK0_MAJOR 8 +#define SCSI_TAPE_MAJOR 9 +#define MD_MAJOR 9 +#define MISC_MAJOR 10 +#define SCSI_CDROM_MAJOR 11 +#define QIC02_TAPE_MAJOR 12 +#define XT_DISK_MAJOR 13 +#define SOUND_MAJOR 14 +#define CDU31A_CDROM_MAJOR 15 +#define JOYSTICK_MAJOR 15 +#define GOLDSTAR_CDROM_MAJOR 16 +#define OPTICS_CDROM_MAJOR 17 +#define SANYO_CDROM_MAJOR 18 +#define CYCLADES_MAJOR 19 +#define CYCLADESAUX_MAJOR 20 +#define MITSUMI_X_CDROM_MAJOR 20 +#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ +#define SCSI_GENERIC_MAJOR 21 +#define Z8530_MAJOR 34 +#define DIGI_MAJOR 23 +#define IDE1_MAJOR 22 +#define DIGICU_MAJOR 22 +#define MITSUMI_CDROM_MAJOR 23 +#define CDU535_CDROM_MAJOR 24 +#define STL_SERIALMAJOR 24 +#define MATSUSHITA_CDROM_MAJOR 25 +#define STL_CALLOUTMAJOR 25 +#define MATSUSHITA_CDROM2_MAJOR 26 +#define QIC117_TAPE_MAJOR 27 +#define MATSUSHITA_CDROM3_MAJOR 27 +#define MATSUSHITA_CDROM4_MAJOR 28 +#define STL_SIOMEMMAJOR 28 +#define ACSI_MAJOR 28 +#define AZTECH_CDROM_MAJOR 29 +#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ +#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ +#define CM206_CDROM_MAJOR 32 +#define IDE2_MAJOR 33 +#define IDE3_MAJOR 34 +#define XPRAM_MAJOR 35 /* expanded storage on S/390 = "slow ram" */ + /* proposed by Peter */ +#define NETLINK_MAJOR 36 +#define PS2ESDI_MAJOR 36 +#define IDETAPE_MAJOR 37 +#define Z2RAM_MAJOR 37 +#define APBLOCK_MAJOR 38 /* AP1000 Block device */ +#define DDV_MAJOR 39 /* AP1000 DDV block device */ +#define NBD_MAJOR 43 /* Network block device */ +#define RISCOM8_NORMAL_MAJOR 48 +#define DAC960_MAJOR 48 /* 48..55 */ +#define RISCOM8_CALLOUT_MAJOR 49 +#define MKISS_MAJOR 55 +#define DSP56K_MAJOR 55 /* DSP56001 processor device */ + +#define IDE4_MAJOR 56 +#define IDE5_MAJOR 57 + +#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ + +#define SCSI_DISK1_MAJOR 65 +#define SCSI_DISK2_MAJOR 66 +#define SCSI_DISK3_MAJOR 67 +#define SCSI_DISK4_MAJOR 68 +#define SCSI_DISK5_MAJOR 69 +#define SCSI_DISK6_MAJOR 70 +#define SCSI_DISK7_MAJOR 71 + + +#define COMPAQ_SMART2_MAJOR 72 +#define COMPAQ_SMART2_MAJOR1 73 +#define COMPAQ_SMART2_MAJOR2 74 +#define COMPAQ_SMART2_MAJOR3 75 +#define COMPAQ_SMART2_MAJOR4 76 +#define COMPAQ_SMART2_MAJOR5 77 +#define COMPAQ_SMART2_MAJOR6 78 +#define COMPAQ_SMART2_MAJOR7 79 + +#define SPECIALIX_NORMAL_MAJOR 75 +#define SPECIALIX_CALLOUT_MAJOR 76 + +#define COMPAQ_CISS_MAJOR 104 +#define COMPAQ_CISS_MAJOR1 105 +#define COMPAQ_CISS_MAJOR2 106 +#define COMPAQ_CISS_MAJOR3 107 +#define COMPAQ_CISS_MAJOR4 108 +#define COMPAQ_CISS_MAJOR5 109 +#define COMPAQ_CISS_MAJOR6 110 +#define COMPAQ_CISS_MAJOR7 111 + +#define ATARAID_MAJOR 114 + +#define DASD_MAJOR 94 /* Official assignations from Peter */ + +#define MDISK_MAJOR 95 /* Official assignations from Peter */ + +#define I2O_MAJOR 80 /* 80->87 */ + +#define IDE6_MAJOR 88 +#define IDE7_MAJOR 89 +#define IDE8_MAJOR 90 +#define IDE9_MAJOR 91 + +#define UBD_MAJOR 98 + +#define AURORA_MAJOR 79 + +#define JSFD_MAJOR 99 + +#define PHONE_MAJOR 100 + +#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ + +#define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ + +#define XLBLK_MAJOR 123 /* XenoLinux Block Device */ + +#define RTF_MAJOR 150 +#define RAW_MAJOR 162 + +#define USB_ACM_MAJOR 166 +#define USB_ACM_AUX_MAJOR 167 +#define USB_CHAR_MAJOR 180 + +#define UNIX98_PTY_MASTER_MAJOR 128 +#define UNIX98_PTY_MAJOR_COUNT 8 +#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) + +#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */ +#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */ +#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */ + +#define MSR_MAJOR 202 +#define CPUID_MAJOR 203 + +#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ + +#define IBM_TTY3270_MAJOR 227 /* Official allocations now */ +#define IBM_FS3270_MAJOR 228 + +/* + * Tests for SCSI devices. + */ + +#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ + ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) + +#define SCSI_BLK_MAJOR(M) \ + (SCSI_DISK_MAJOR(M) \ + || (M) == SCSI_CDROM_MAJOR) + +static __inline__ int scsi_blk_major(int m) { + return SCSI_BLK_MAJOR(m); +} + +/* + * Tests for IDE devices + */ +#define IDE_DISK_MAJOR(M) ((M) == IDE0_MAJOR || (M) == IDE1_MAJOR || \ + (M) == IDE2_MAJOR || (M) == IDE3_MAJOR || \ + (M) == IDE4_MAJOR || (M) == IDE5_MAJOR || \ + (M) == IDE6_MAJOR || (M) == IDE7_MAJOR || \ + (M) == IDE8_MAJOR || (M) == IDE9_MAJOR) + +static __inline__ int ide_blk_major(int m) +{ + return IDE_DISK_MAJOR(m); +} + +#endif diff --git a/xenolinux-2.4.16-sparse/init/main.c b/xenolinux-2.4.16-sparse/init/main.c new file mode 100644 index 0000000000..a48a7773b8 --- /dev/null +++ b/xenolinux-2.4.16-sparse/init/main.c @@ -0,0 +1,871 @@ +/* + * linux/init/main.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * GK 2/5/95 - Changed to support mounting root fs via NFS + * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 + * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 + * Simplified starting of init: Michael A. Griffith <grif@acm.org> + */ + +#define __KERNEL_SYSCALLS__ + +#include <linux/config.h> +#include <linux/proc_fs.h> +#include <linux/devfs_fs_kernel.h> +#include <linux/unistd.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/delay.h> +#include <linux/utsname.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/smp_lock.h> +#include <linux/blk.h> +#include <linux/hdreg.h> +#include <linux/iobuf.h> +#include <linux/bootmem.h> +#include <linux/tty.h> + +#include <asm/io.h> +#include <asm/bugs.h> + +#if defined(CONFIG_ARCH_S390) +#include <asm/s390mach.h> +#include <asm/ccwcache.h> +#endif + +#ifdef CONFIG_PCI +#include <linux/pci.h> +#endif + +#ifdef CONFIG_DIO +#include <linux/dio.h> +#endif + +#ifdef CONFIG_ZORRO +#include <linux/zorro.h> +#endif + +#ifdef CONFIG_MTRR +# include <asm/mtrr.h> +#endif + +#ifdef CONFIG_NUBUS +#include <linux/nubus.h> +#endif + +#ifdef CONFIG_ISAPNP +#include <linux/isapnp.h> +#endif + +#ifdef CONFIG_IRDA +extern int irda_proto_init(void); +extern int irda_device_init(void); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC +#include <asm/smp.h> +#endif + +#if defined(CONFIG_KDB) +#include <linux/kdb.h> +#endif + +/* + * Versions of gcc older than that listed below may actually compile + * and link okay, but the end product can have subtle run time bugs. + * To avoid associated bogus bug reports, we flatly refuse to compile + * with a gcc that is known to be too old from the very beginning. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91) +#error Sorry, your GCC is too old. It builds incorrect kernels. +#endif + +extern char _stext, _etext; +extern char *linux_banner; + +static int init(void *); + +extern void init_IRQ(void); +extern void init_modules(void); +extern void sock_init(void); +extern void fork_init(unsigned long); +extern void mca_init(void); +extern void sbus_init(void); +extern void ppc_init(void); +extern void sysctl_init(void); +extern void signals_init(void); +extern int init_pcmcia_ds(void); + +extern void free_initmem(void); + +#ifdef CONFIG_TC +extern void tc_init(void); +#endif + +extern void ecard_init(void); + +#if defined(CONFIG_SYSVIPC) +extern void ipc_init(void); +#endif + +/* + * Boot command-line arguments + */ +#define MAX_INIT_ARGS 8 +#define MAX_INIT_ENVS 8 + +extern void time_init(void); +extern void softirq_init(void); + +int rows, cols; + +#ifdef CONFIG_BLK_DEV_INITRD +unsigned int real_root_dev; /* do_proc_dointvec cannot handle kdev_t */ +#endif + +int root_mountflags = MS_RDONLY; +char *execute_command; +char root_device_name[64]; + + +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; +static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; + +static int __init profile_setup(char *str) +{ + int par; + if (get_option(&str,&par)) prof_shift = par; + return 1; +} + +__setup("profile=", profile_setup); + + +static struct dev_name_struct { + const char *name; + const int num; +} root_dev_names[] __initdata = { + { "nfs", 0x00ff }, + { "blk", 0x7b00 }, + { "hda", 0x0300 }, + { "hdb", 0x0340 }, + { "loop", 0x0700 }, + { "hdc", 0x1600 }, + { "hdd", 0x1640 }, + { "hde", 0x2100 }, + { "hdf", 0x2140 }, + { "hdg", 0x2200 }, + { "hdh", 0x2240 }, + { "hdi", 0x3800 }, + { "hdj", 0x3840 }, + { "hdk", 0x3900 }, + { "hdl", 0x3940 }, + { "hdm", 0x5800 }, + { "hdn", 0x5840 }, + { "hdo", 0x5900 }, + { "hdp", 0x5940 }, + { "hdq", 0x5A00 }, + { "hdr", 0x5A40 }, + { "hds", 0x5B00 }, + { "hdt", 0x5B40 }, + { "sda", 0x0800 }, + { "sdb", 0x0810 }, + { "sdc", 0x0820 }, + { "sdd", 0x0830 }, + { "sde", 0x0840 }, + { "sdf", 0x0850 }, + { "sdg", 0x0860 }, + { "sdh", 0x0870 }, + { "sdi", 0x0880 }, + { "sdj", 0x0890 }, + { "sdk", 0x08a0 }, + { "sdl", 0x08b0 }, + { "sdm", 0x08c0 }, + { "sdn", 0x08d0 }, + { "sdo", 0x08e0 }, + { "sdp", 0x08f0 }, + { "ada", 0x1c00 }, + { "adb", 0x1c10 }, + { "adc", 0x1c20 }, + { "add", 0x1c30 }, + { "ade", 0x1c40 }, + { "fd", 0x0200 }, + { "md", 0x0900 }, + { "xda", 0x0d00 }, + { "xdb", 0x0d40 }, + { "ram", 0x0100 }, + { "scd", 0x0b00 }, + { "mcd", 0x1700 }, + { "cdu535", 0x1800 }, + { "sonycd", 0x1800 }, + { "aztcd", 0x1d00 }, + { "cm206cd", 0x2000 }, + { "gscd", 0x1000 }, + { "sbpcd", 0x1900 }, + { "eda", 0x2400 }, + { "edb", 0x2440 }, + { "pda", 0x2d00 }, + { "pdb", 0x2d10 }, + { "pdc", 0x2d20 }, + { "pdd", 0x2d30 }, + { "pcd", 0x2e00 }, + { "pf", 0x2f00 }, + { "apblock", APBLOCK_MAJOR << 8}, + { "ddv", DDV_MAJOR << 8}, + { "jsfd", JSFD_MAJOR << 8}, +#if defined(CONFIG_ARCH_S390) + { "dasda", (DASD_MAJOR << MINORBITS) }, + { "dasdb", (DASD_MAJOR << MINORBITS) + (1 << 2) }, + { "dasdc", (DASD_MAJOR << MINORBITS) + (2 << 2) }, + { "dasdd", (DASD_MAJOR << MINORBITS) + (3 << 2) }, + { "dasde", (DASD_MAJOR << MINORBITS) + (4 << 2) }, + { "dasdf", (DASD_MAJOR << MINORBITS) + (5 << 2) }, + { "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) }, + { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) }, +#endif +#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE) + { "ida/c0d0p",0x4800 }, + { "ida/c0d1p",0x4810 }, + { "ida/c0d2p",0x4820 }, + { "ida/c0d3p",0x4830 }, + { "ida/c0d4p",0x4840 }, + { "ida/c0d5p",0x4850 }, + { "ida/c0d6p",0x4860 }, + { "ida/c0d7p",0x4870 }, + { "ida/c0d8p",0x4880 }, + { "ida/c0d9p",0x4890 }, + { "ida/c0d10p",0x48A0 }, + { "ida/c0d11p",0x48B0 }, + { "ida/c0d12p",0x48C0 }, + { "ida/c0d13p",0x48D0 }, + { "ida/c0d14p",0x48E0 }, + { "ida/c0d15p",0x48F0 }, +#endif +#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE) + { "cciss/c0d0p",0x6800 }, + { "cciss/c0d1p",0x6810 }, + { "cciss/c0d2p",0x6820 }, + { "cciss/c0d3p",0x6830 }, + { "cciss/c0d4p",0x6840 }, + { "cciss/c0d5p",0x6850 }, + { "cciss/c0d6p",0x6860 }, + { "cciss/c0d7p",0x6870 }, + { "cciss/c0d8p",0x6880 }, + { "cciss/c0d9p",0x6890 }, + { "cciss/c0d10p",0x68A0 }, + { "cciss/c0d11p",0x68B0 }, + { "cciss/c0d12p",0x68C0 }, + { "cciss/c0d13p",0x68D0 }, + { "cciss/c0d14p",0x68E0 }, + { "cciss/c0d15p",0x68F0 }, +#endif + { "nftla", 0x5d00 }, + { "nftlb", 0x5d10 }, + { "nftlc", 0x5d20 }, + { "nftld", 0x5d30 }, + { "ftla", 0x2c00 }, + { "ftlb", 0x2c08 }, + { "ftlc", 0x2c10 }, + { "ftld", 0x2c18 }, + { "mtdblock", 0x1f00 }, + { NULL, 0 } +}; + +kdev_t __init name_to_kdev_t(char *line) +{ + int base = 0; + + if (strncmp(line,"/dev/",5) == 0) { + struct dev_name_struct *dev = root_dev_names; + line += 5; + do { + int len = strlen(dev->name); + if (strncmp(line,dev->name,len) == 0) { + line += len; + base = dev->num; + break; + } + dev++; + } while (dev->name); + } + return to_kdev_t(base + simple_strtoul(line,NULL,base?10:16)); +} + +static int __init root_dev_setup(char *line) +{ + int i; + char ch; + + ROOT_DEV = name_to_kdev_t(line); + memset (root_device_name, 0, sizeof root_device_name); + if (strncmp (line, "/dev/", 5) == 0) line += 5; + for (i = 0; i < sizeof root_device_name - 1; ++i) + { + ch = line[i]; + if ( isspace (ch) || (ch == ',') || (ch == '\0') ) break; + root_device_name[i] = ch; + } + return 1; +} + +__setup("root=", root_dev_setup); + +static int __init checksetup(char *line) +{ + struct kernel_param *p; + + p = &__setup_start; + do { + int n = strlen(p->str); + if (!strncmp(line,p->str,n)) { + if (p->setup_func(line+n)) + return 1; + } + p++; + } while (p < &__setup_end); + return 0; +} + +/* this should be approx 2 Bo*oMips to start (note initial shift), and will + still work even if initially too large, it will just take slightly longer */ +unsigned long loops_per_jiffy = (1<<12); + +/* This is the number of bits of precision for the loops_per_jiffy. Each + bit takes on average 1.5/HZ seconds. This (like the original) is a little + better than 1% */ +#define LPS_PREC 8 + +void __init calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + loops_per_jiffy = (1<<12); + + printk("Calibrating delay loop... "); + while (loops_per_jiffy <<= 1) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + +/* Do a binary approximation to get loops_per_jiffy set to equal one clock + (up to lps_precision bits) */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while ( lps_precision-- && (loopbit >>= 1) ) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies); + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } + +/* Round the value and print it */ + printk("%lu.%02lu BogoMIPS\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} + +static int __init readonly(char *str) +{ + if (*str) + return 0; + root_mountflags |= MS_RDONLY; + return 1; +} + +static int __init readwrite(char *str) +{ + if (*str) + return 0; + root_mountflags &= ~MS_RDONLY; + return 1; +} + +static int __init debug_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 10; + return 1; +} + +static int __init quiet_kernel(char *str) +{ + if (*str) + return 0; + console_loglevel = 4; + return 1; +} + +__setup("ro", readonly); +__setup("rw", readwrite); +__setup("debug", debug_kernel); +__setup("quiet", quiet_kernel); + +/* + * This is a simple kernel command line parsing function: it parses + * the command line, and fills in the arguments/environment to init + * as appropriate. Any cmd-line option is taken to be an environment + * variable if it contains the character '='. + * + * This routine also checks for options meant for the kernel. + * These options are not given to init - they are for internal kernel use only. + */ +static void __init parse_options(char *line) +{ + char *next,*quote; + int args, envs; + + if (!*line) + return; + args = 0; + envs = 1; /* TERM is set to 'linux' by default */ + next = line; + while ((line = next) != NULL) { + quote = strchr(line,'"'); + next = strchr(line, ' '); + while (next != NULL && quote != NULL && quote < next) { + /* we found a left quote before the next blank + * now we have to find the matching right quote + */ + next = strchr(quote+1, '"'); + if (next != NULL) { + quote = strchr(next+1, '"'); + next = strchr(next+1, ' '); + } + } + if (next != NULL) + *next++ = 0; +#if defined(CONFIG_KDB) + /* kdb, kdb=on, kdb=off, kdb=early */ + if (strncmp(line, "kdb", 3) == 0) { + if (line[3] == '\0') { + /* Backward compatibility, kdb with no option means early activation */ + printk("Boot flag kdb with no options is obsolete, use kdb=early\n"); + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + if (line[3] == '=') { + if (strcmp(line+4, "on") == 0) { + kdb_on = 1; + continue; + } + if (strcmp(line+4, "off") == 0) { + kdb_on = 0; + continue; + } + if (strcmp(line+4, "early") == 0) { + kdb_on = 1; + kdb_flags |= KDB_FLAG_EARLYKDB; + continue; + } + printk("Boot flag %s not recognised, assumed to be environment variable\n", line); + } + } +#endif + if (!strncmp(line,"init=",5)) { + line += 5; + execute_command = line; + /* In case LILO is going to boot us with default command line, + * it prepends "auto" before the whole cmdline which makes + * the shell think it should execute a script with such name. + * So we ignore all arguments entered _before_ init=... [MJ] + */ + args = 0; + continue; + } + if (checksetup(line)) + continue; + + /* + * Then check if it's an environment variable or + * an option. + */ + if (strchr(line,'=')) { + if (envs >= MAX_INIT_ENVS) + break; + envp_init[++envs] = line; + } else { + if (args >= MAX_INIT_ARGS) + break; + if (*line) + argv_init[++args] = line; + } + } + argv_init[args+1] = NULL; + envp_init[envs+1] = NULL; +} + + +extern void setup_arch(char **); +extern void cpu_idle(void); + +unsigned long wait_init_idle; + +#ifndef CONFIG_SMP + +#ifdef CONFIG_X86_LOCAL_APIC +static void __init smp_init(void) +{ + APIC_init_uniprocessor(); +} +#else +#define smp_init() do { } while (0) +#endif + +#else + + +/* Called by boot processor to activate the rest. */ +static void __init smp_init(void) +{ + /* Get other processors into their bootup holding patterns. */ + smp_boot_cpus(); + wait_init_idle = cpu_online_map; + clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */ + + smp_threads_ready=1; + smp_commence(); + + /* Wait for the other cpus to set up their idle processes */ + printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle); + while (wait_init_idle) { + cpu_relax(); + barrier(); + } + printk("All processors have done init_idle\n"); +} + +#endif + +/* + * We need to finalize in a non-__init function or else race conditions + * between the root thread and the init thread may cause start_kernel to + * be reaped by free_initmem before the root thread has proceeded to + * cpu_idle. + */ + +static void rest_init(void) +{ + kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + unlock_kernel(); + current->need_resched = 1; + cpu_idle(); +} + +/* + * Activate the first processor. + */ + +asmlinkage void __init start_kernel(void) +{ + char * command_line; + unsigned long mempages; + extern char saved_command_line[]; +/* + * Interrupts are still disabled. Do necessary setups, then + * enable them + */ + lock_kernel(); + printk(linux_banner); + setup_arch(&command_line); + printk("Kernel command line: %s\n", saved_command_line); + parse_options(command_line); + trap_init(); + init_IRQ(); + sched_init(); + softirq_init(); + time_init(); + + /* + * HACK ALERT! This is early. We're enabling the console before + * we've done PCI setups etc, and console_init() must be aware of + * this. But we do want output early, in case something goes wrong. + */ + console_init(); +#ifdef CONFIG_MODULES + init_modules(); +#endif + if (prof_shift) { + unsigned int size; + /* only text is profiled */ + prof_len = (unsigned long) &_etext - (unsigned long) &_stext; + prof_len >>= prof_shift; + + size = prof_len * sizeof(unsigned int) + PAGE_SIZE-1; + prof_buffer = (unsigned int *) alloc_bootmem(size); + } + + kmem_cache_init(); + sti(); + calibrate_delay(); +#ifdef CONFIG_BLK_DEV_INITRD + if (initrd_start && !initrd_below_start_ok && + initrd_start < min_low_pfn << PAGE_SHIFT) { + printk(KERN_CRIT "initrd overwritten (0x%08lx < 0x%08lx) - " + "disabling it.\n",initrd_start,min_low_pfn << PAGE_SHIFT); + initrd_start = 0; + } +#endif + mem_init(); + kmem_cache_sizes_init(); +#if defined(CONFIG_KDB) + kdb_init(); + if (KDB_FLAG(EARLYKDB)) { + KDB_ENTER(); + } +#endif + mempages = num_physpages; + + fork_init(mempages); + proc_caches_init(); + vfs_caches_init(mempages); + buffer_init(mempages); + page_cache_init(mempages); +#if defined(CONFIG_ARCH_S390) + ccwcache_init(); +#endif + signals_init(); +#ifdef CONFIG_PROC_FS + proc_root_init(); +#endif +#if defined(CONFIG_SYSVIPC) + ipc_init(); +#endif + check_bugs(); + printk("POSIX conformance testing by UNIFIX\n"); + + /* + * We count on the initial thread going ok + * Like idlers init is an unlocked kernel thread, which will + * make syscalls (and thus be locked). + */ + smp_init(); + rest_init(); +} + +#ifdef CONFIG_BLK_DEV_INITRD +static int do_linuxrc(void * shell) +{ + static char *argv[] = { "linuxrc", NULL, }; + + close(0);close(1);close(2); + setsid(); + (void) open("/dev/console",O_RDWR,0); + (void) dup(0); + (void) dup(0); + return execve(shell, argv, envp_init); +} + +#endif + +struct task_struct *child_reaper = &init_task; + +static void __init do_initcalls(void) +{ + initcall_t *call; + + call = &__initcall_start; + do { + (*call)(); + call++; + } while (call < &__initcall_end); + + /* Make sure there is no pending stuff from the initcall sequence */ + flush_scheduled_tasks(); +} + +/* + * Ok, the machine is now initialized. None of the devices + * have been touched yet, but the CPU subsystem is up and + * running, and memory and process management works. + * + * Now we can finally start doing some real work.. + */ +static void __init do_basic_setup(void) +{ + + /* + * Tell the world that we're going to be the grim + * reaper of innocent orphaned children. + * + * We don't want people to have to make incorrect + * assumptions about where in the task array this + * can be found. + */ + child_reaper = current; + +#if defined(CONFIG_MTRR) /* Do this after SMP initialization */ +/* + * We should probably create some architecture-dependent "fixup after + * everything is up" style function where this would belong better + * than in init/main.c.. + */ + mtrr_init(); +#endif + +#ifdef CONFIG_SYSCTL + sysctl_init(); +#endif + + /* + * Ok, at this point all CPU's should be initialized, so + * we can start looking into devices.. + */ +#if defined(CONFIG_ARCH_S390) + s390_init_machine_check(); +#endif + +#ifdef CONFIG_PCI + pci_init(); +#endif +#ifdef CONFIG_SBUS + sbus_init(); +#endif +#if defined(CONFIG_PPC) + ppc_init(); +#endif +#ifdef CONFIG_MCA + mca_init(); +#endif +#ifdef CONFIG_ARCH_ACORN + ecard_init(); +#endif +#ifdef CONFIG_ZORRO + zorro_init(); +#endif +#ifdef CONFIG_DIO + dio_init(); +#endif +#ifdef CONFIG_NUBUS + nubus_init(); +#endif +#ifdef CONFIG_ISAPNP + isapnp_init(); +#endif +#ifdef CONFIG_TC + tc_init(); +#endif + + /* Networking initialization needs a process context */ + sock_init(); + + start_context_thread(); + do_initcalls(); + +#ifdef CONFIG_IRDA + irda_proto_init(); + irda_device_init(); /* Must be done after protocol initialization */ +#endif +#ifdef CONFIG_PCMCIA + init_pcmcia_ds(); /* Do this last */ +#endif +} + +extern void rd_load(void); +extern void initrd_load(void); + +/* + * Prepare the namespace - decide what/where to mount, load ramdisks, etc. + */ +static void prepare_namespace(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD + int real_root_mountflags = root_mountflags; + if (!initrd_start) + mount_initrd = 0; + if (mount_initrd) + root_mountflags &= ~MS_RDONLY; + real_root_dev = ROOT_DEV; +#endif + +#ifdef CONFIG_BLK_DEV_RAM +#ifdef CONFIG_BLK_DEV_INITRD + if (mount_initrd) + initrd_load(); + else +#endif + rd_load(); +#endif + + /* Mount the root filesystem.. */ + mount_root(); + + mount_devfs_fs (); + +#ifdef CONFIG_BLK_DEV_INITRD + root_mountflags = real_root_mountflags; + if (mount_initrd && ROOT_DEV != real_root_dev + && MAJOR(ROOT_DEV) == RAMDISK_MAJOR && MINOR(ROOT_DEV) == 0) { + int error; + int i, pid; + + pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); + if (pid > 0) { + while (pid != wait(&i)) { + current->policy |= SCHED_YIELD; + schedule(); + } + } + if (MAJOR(real_root_dev) != RAMDISK_MAJOR + || MINOR(real_root_dev) != 0) { + error = change_root(real_root_dev,"/initrd"); + if (error) + printk(KERN_ERR "Change root to /initrd: " + "error %d\n",error); + } + } +#endif +} + +static int init(void * unused) +{ + lock_kernel(); + do_basic_setup(); + + prepare_namespace(); + + /* + * Ok, we have completed the initial bootup, and + * we're essentially up and running. Get rid of the + * initmem segments and start the user-mode stuff.. + */ + free_initmem(); + unlock_kernel(); + + if (open("/dev/console", O_RDWR, 0) < 0) + printk("Warning: unable to open an initial console.\n"); + + (void) dup(0); + (void) dup(0); + + /* + * We try each of these until one succeeds. + * + * The Bourne shell can be used instead of init if we are + * trying to recover a really broken machine. + */ + + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); + execve("/bin/sh",argv_init,envp_init); + panic("No init found. Try passing init= option to kernel."); +} |