bitkeeper revision 1.22.2.15 (3e4a8cc5yR9FrJ4VfvYBJMEgnf67Kw)

Merge boulderdash.cl.cam.ac.uk:/usr/groups/xeno/BK/xeno
into boulderdash.cl.cam.ac.uk:/local/scratch/smh22/xeno.bk
This commit is contained in:
smh22@boulderdash.cl.cam.ac.uk committed 2003-02-12 18:04:53 +00:00
commit a9495f0f61
16 files changed
+6123

No files matched your search

+14
View File
@@ -57,8 +57,13 @@
3ddb79beME_0abStePF6fU8XLuQnWw xen-2.4.16/drivers/block/elevator.c
3ddb79beNQVrdGyoI4njXhgAjD6a4A xen-2.4.16/drivers/block/genhd.c
3ddb79beyWwLRP_BiM2t1JKgr_plEw xen-2.4.16/drivers/block/ll_rw_blk.c
3e4a8cb7RhubVgsPwO7cK0pgAN8WCQ xen-2.4.16/drivers/block/xen_block.c
3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen-2.4.16/drivers/char/Makefile
3e4a8cb7WmiYdC-ASGiCSG_CL8vsqg xen-2.4.16/drivers/char/xen_kbd.c
3e4a8cb7nMChlro4wvOBo76n__iCFA xen-2.4.16/drivers/char/xen_serial.c
3ddb79bdhcqD9ebrslr0O0oHqTiiXg xen-2.4.16/drivers/ide/Makefile
3ddb79bdErDn_WC3G-fWxKNR3viLnA xen-2.4.16/drivers/ide/ide-disk.c
3e4a8cb7DcFFHW_fG_OHbY_6f3lPWw xen-2.4.16/drivers/ide/ide-disk.c.orig
3ddb79bdIPNW36FrlId94jTXaW8HoA xen-2.4.16/drivers/ide/ide-dma.c
3ddb79be5Ysvhn4se_Z-LQY_hI6UPw xen-2.4.16/drivers/ide/ide-features.c
3ddb79bdh1ohsWYRH_KdaXr7cqs12w xen-2.4.16/drivers/ide/ide-geometry.c
@@ -267,9 +272,12 @@
3ddb79b7v_Be34as7_mlzFlw65hOjQ xenolinux-2.4.16-sparse/arch/xeno/defconfig
3ddb79b7KUvtx0knQJoRaBDZQeNidg xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile
3ddb79b6Rc0uAOGFthIFxq1KGWZ_Iw xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c
3e4a8cb7JECr--r1ipnrkd7NKdbUqQ xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block.c
3e4a8cb7SLWsLTXQjv7ng6-3hL4pCA xenolinux-2.4.16-sparse/arch/xeno/drivers/block/xl_block_test.c
3ddb79b7LLVJBGynxHSOh9A9l97sug xenolinux-2.4.16-sparse/arch/xeno/drivers/console/Makefile
3ddb79b7UG2QiRAU-Wvc1Y_BLigu1Q xenolinux-2.4.16-sparse/arch/xeno/drivers/console/console.c
3ddb79b75eo4PRXkT6Th9popt_SJhg xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/Makefile
3e4a8cb79dT0F4q5T4GEqMj4CtAquQ xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_block.c
3ddb79b7Xyaoep6U0kLvx6Kx7OauDw xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_core.c
3df9ce13K7qSLBtHV-01QHPW62649Q xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_memory.c
3ddb79b7PulSkF9m3c7K5MkxHRf4hA xenolinux-2.4.16-sparse/arch/xeno/drivers/dom0/dom0_ops.h
@@ -313,10 +321,13 @@
3ddb79b83Zj7Xn2QVhU4HeMuAC9FjA xenolinux-2.4.16-sparse/arch/xeno/mm/init.c
3df9ce13TRWIv0Mawm15zESP7jcT7A xenolinux-2.4.16-sparse/arch/xeno/mm/mmu_context.c
3ddb79b7aKdTkbr3u6aze8tVwGh_TQ xenolinux-2.4.16-sparse/arch/xeno/vmlinux.lds
3e4a8cb7lpFFwT1Iu9zXWc8Ew4klFA xenolinux-2.4.16-sparse/drivers/block/Config.in
3ddb79bbx682YH6vR2zbVOXwg73ULg xenolinux-2.4.16-sparse/drivers/block/ll_rw_blk.c
3ddb79bcJfHdwrPsjqgI33_OsGdVCg xenolinux-2.4.16-sparse/drivers/block/rd.c
3ddb79bcpVu-IbnqwQqpRqsEbLpsuw xenolinux-2.4.16-sparse/drivers/char/tty_io.c
3e15d5273gfR2fbcYe05kqBSAvCX_w xenolinux-2.4.16-sparse/fs/exec.c
3e4a8cb7kqfJTMeOpPcYxqxv7N18DA xenolinux-2.4.16-sparse/fs/partitions/check.c
3e4a8cb7p079Xxly4uNcouacMSjJLw xenolinux-2.4.16-sparse/fs/partitions/msdos.c
3ddb79b8VFtfWSCrXKPN2K21zd_vtw xenolinux-2.4.16-sparse/include/asm-xeno/a.out.h
3ddb79b8Zzi13p3OAPV25QgiC3THAQ xenolinux-2.4.16-sparse/include/asm-xeno/apic.h
3ddb79baZDlsdV_m6C5CXnWMl15p1g xenolinux-2.4.16-sparse/include/asm-xeno/apicdef.h
@@ -422,7 +433,10 @@
3ddb79ba2qYtIQAT_-vCFkkZUXu_UQ xenolinux-2.4.16-sparse/include/asm-xeno/user.h
3ddb79bbqhb9X9qWOz5Bv4wOzrkITg xenolinux-2.4.16-sparse/include/asm-xeno/vga.h
3ddb79bbA52x94o6uwDYsbzrH2hjzA xenolinux-2.4.16-sparse/include/asm-xeno/xor.h
3e4a8cb7ON8EclY3NN3YPXyMT941hA xenolinux-2.4.16-sparse/include/linux/blk.h
3e4a8cb7GJrKD0z7EF0VZOhdEa01Mw xenolinux-2.4.16-sparse/include/linux/major.h
3ddb79bb_7YG4U75ZmEic9YXWTW7Vw xenolinux-2.4.16-sparse/include/linux/sunrpc/debug.h
3e4a8cb7j05wwb1uPZgY16s68o7qAw xenolinux-2.4.16-sparse/init/main.c
3ddb79bcxkVPfWlZ1PQKvDrfArzOVw xenolinux-2.4.16-sparse/kernel/panic.c
3ddb79bbP31im-mx2NbfthSeqty1Dg xenolinux-2.4.16-sparse/mk
3e15d52e0_j129JPvo7xfYGndVFpwQ xenolinux-2.4.16-sparse/mm/memory.c
+16
View File
@@ -3,3 +3,19 @@ PENDING/*
xen-2.4.16/common/kernel.c.old
xen-2.4.16/common/kernel.c.ok-ish
xen-2.4.16/size.image
xen-2.4.16/drivers/block/ll_rw_blk.c.orig
xen-2.4.16/drivers/ide/ide-disk.c.orig
xen-2.4.16/drivers/ide/ide-probe.c.orig
xen-2.4.16/drivers/ide/ide-taskfile.c.orig
xen-2.4.16/drivers/ide/ide.c.orig
xen-2.4.16/drivers/net/e1000/e1000.o
xen-2.4.16/drivers/net/e1000/e1000_ethtool.o
xen-2.4.16/drivers/net/e1000/e1000_hw.o
xen-2.4.16/drivers/net/e1000/e1000_main.o
xen-2.4.16/drivers/net/e1000/e1000_param.o
xen-2.4.16/include/hypervisor-ifs/block.h.orig
xen-2.4.16/include/xeno/blkdev.h.orig
xen-2.4.16/include/xeno/sched.h.orig
xenolinux-2.4.16-sparse/arch/xeno/drivers/block/Makefile.orig
xenolinux-2.4.16-sparse/arch/xeno/drivers/block/block.c.orig
xenolinux-2.4.16-sparse/scripts/kconfig.tk
+620
View File
@@ -0,0 +1,620 @@
/*
* xen-block.c
*
* process incoming block io requests from guestos's.
*/
#include <xeno/config.h>
#include <xeno/types.h>
#include <xeno/lib.h>
#include <xeno/sched.h>
#include <xeno/blkdev.h>
#include <xeno/event.h> /* mark_hyp_event */
#include <hypervisor-ifs/block.h>
#include <hypervisor-ifs/hypervisor-if.h>
#include <asm-i386/io.h>
#include <asm/spinlock.h>
#define XEN_BLK_DEBUG 0
#define XEN_BLK_DEBUG_LEVEL KERN_ALERT
#define XEN_BLK_REQUEST_LIST_SIZE 256 /* very arbitrary */
typedef struct blk_request
{
struct list_head queue;
struct buffer_head *bh;
blk_ring_entry_t request;
struct task_struct *domain; /* requesting domain */
} blk_request_t;
static int pending_work; /* which domains have work for us? */
blk_request_t blk_request_list[XEN_BLK_REQUEST_LIST_SIZE];
struct list_head free_queue; /* unused requests */
struct list_head pending_queue; /* waiting for hardware */
struct list_head io_done_queue; /* request completed. send to guest os */
spinlock_t free_queue_lock;
spinlock_t pending_queue_lock;
spinlock_t io_done_queue_lock;
/* some definitions */
void dumpx (char *buffer, int count);
void printx (char * string);
long do_block_io_op_domain (struct task_struct* task);
int dispatch_rw_block_io (int index);
int dispatch_probe_block_io (int index);
int dispatch_debug_block_io (int index);
/*
* end_block_io_op
*
* IO has completed. Need to notify the guest operating system.
* Called from hardware interrupt.
*/
void end_block_io_op(struct buffer_head * bh)
{
unsigned long cpu_mask;
/* struct list_head *list;*/
blk_request_t *blk_request = NULL;
unsigned long flags; /* irq save */
#if 0
printk("{E}");
#endif
if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL
"XEN end_block_io_op, bh: %lx\n",
(unsigned long)bh);
{
char temp[100];
sprintf(temp, "endio bh: 0x%p, blkno: 0x%lx",
bh, bh->b_blocknr);
printx(temp);
}
spin_lock_irqsave(&pending_queue_lock, flags);
/*
list_for_each (list, &pending_queue)
{
blk_request = list_entry(list, blk_request_t, queue);
if (blk_request->bh == bh)
{
break;
}
}
*/
blk_request = (blk_request_t *)bh->b_xen_request;
if (blk_request == NULL)
{
printk (KERN_ALERT
" block io interrupt received for unknown buffer [0x%lx]\n",
(unsigned long) bh);
spin_unlock_irqrestore(&pending_queue_lock, flags);
return;
}
list_del(&blk_request->queue);
spin_unlock_irqrestore(&pending_queue_lock, flags);
spin_lock_irqsave(&io_done_queue_lock, flags);
list_add_tail(&blk_request->queue, &io_done_queue);
spin_unlock_irqrestore(&io_done_queue_lock, flags);
/* enqueue work */
cpu_mask = mark_hyp_event(blk_request->domain, _HYP_EVENT_BLK_RX);
return;
}
/*
* flush_blk_queue
*
* Called by the hypervisor synchronously when there is something to do
* (block transfers have completed)
*/
void flush_blk_queue(void)
{
blk_request_t *blk_request;
int position = 0;
blk_ring_t *blk_ring;
unsigned long flags;
int loop;
#if 0
printk("{F}");
#endif
/*
if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL
"XEN flush_blk_queue\n");
*/
clear_bit(_HYP_EVENT_BLK_RX, &current->hyp_events);
/* NEED LOCK? */
spin_lock_irqsave(&io_done_queue_lock, flags);
while (!list_empty(&io_done_queue))
{
blk_request = list_entry(io_done_queue.next, blk_request_t, queue);
list_del (&blk_request->queue);
spin_unlock_irqrestore(&io_done_queue_lock, flags);
/* place on ring for guest os */
blk_ring = blk_request->domain->blk_ring_base;
position = blk_ring->rx_prod;
if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL
"XEN flush_blk_queue [%d]\n", position);
memcpy(&blk_ring->rx_ring[position], &blk_request->request,
sizeof(blk_ring_entry_t));
blk_ring->rx_prod = BLK_RX_RING_INC(blk_ring->rx_prod);
/* notify appropriate guest os */
set_bit(_EVENT_BLK_RX,
&blk_request->domain->shared_info->events);
if (0)
{
int temp;
struct buffer_head *bh = blk_request->bh;
char * vbuffer = bh->b_data;
printk (KERN_ALERT "XEN return block 0x%lx\n", bh->b_blocknr);
for (temp = 0; temp < bh->b_size; temp++)
{
if (temp % 16 == 0) printk ("[%04x] ", temp);
else if (temp % 4 == 0) printk (" ");
printk ("%02x",
vbuffer[temp] & 255);
if ((temp + 1) % 16 == 0) printk ("\n");
}
printk ("\n\n");
}
/* free the buffer header allocated in do_block_io_op */
if (blk_request->bh)
{
kfree(blk_request->bh); /* alloc in do_block_io_op */
}
spin_lock_irqsave(&free_queue_lock, flags);
list_add_tail(&blk_request->queue, &free_queue);
spin_unlock_irqrestore(&free_queue_lock, flags);
spin_lock_irqsave(&io_done_queue_lock, flags);
}
spin_unlock_irqrestore(&io_done_queue_lock, flags);
/*
* now check if there is any pending work from any domain
* that we were previously unable to process.
*
* NOTE: the current algorithm will check _every_ domain
* and wake up _every_ domain that has pending work.
* In the future, we should stop waking up domains once
* there isn't any space for their requests any more
* ALSO, we need to maintain a counter of the last domain
* that we woke up for fairness... we shouldn't restart
* at domain 0 every time (although we might want to special
* case domain 0);
*/
for (loop = 0; loop < XEN_BLOCK_MAX_DOMAINS; loop++)
{
int domain = pending_work & (1 << loop);
if (domain)
{
struct task_struct *mytask = current;
/*
printk (KERN_ALERT
"flush_blk_queue pending_work: %x domain: %d loop: %d\n",
pending_work, domain, loop);
*/
/* IS THERE A BETTER WAY OF FINDING THE TASK STRUCT FOR A
* PARTICULAR DOMAIN?
*
* WHAT IF THE TASK GOES AWAY BEFORE WE HAVE A CHANCE TO
* FINISH PROCESSING ALL OF ITS REQUESTS?
*/
while (mytask->domain != loop)
{
mytask = mytask->next_task;
}
do_block_io_op_domain(mytask);
pending_work = pending_work & !(1 << loop);
/*
printk (KERN_ALERT
" pending_work: %x domain: %d loop: %d\n",
pending_work, domain, loop);
*/
}
}
}
/*
* do_block_io_op
*
* Accept a block io request from a guest operating system.
* There is an entry in the hypervisor_call_table (xen/arch/i386/entry.S).
*/
long do_block_io_op (void)
{
return do_block_io_op_domain(current);
}
/*
* do_block_io_op
*
* handle the requests for a particular domain
*/
long do_block_io_op_domain (struct task_struct* task)
{
blk_ring_t *blk_ring = task->blk_ring_base;
int loop;
#if 0
printk("{%d}", current->domain);
#endif
if (XEN_BLK_DEBUG) printk(XEN_BLK_DEBUG_LEVEL
"XEN do_block_io_op %d %d\n",
blk_ring->tx_cons, blk_ring->tx_prod);
for (loop = blk_ring->tx_cons;
loop != blk_ring->tx_prod;
loop = BLK_TX_RING_INC(loop))
{
int status = 1;
switch (blk_ring->tx_ring[loop].operation)
{
case XEN_BLOCK_READ :
case XEN_BLOCK_WRITE :
{
status = dispatch_rw_block_io(loop);
break;
}
case XEN_BLOCK_PROBE :
{
status = dispatch_probe_block_io(loop);
break;
}
case XEN_BLOCK_DEBUG :
{
status = dispatch_debug_block_io(loop);
break;
}
default :
{
printk (KERN_ALERT "error: unknown block io operation [%d]\n",
blk_ring->tx_ring[loop].operation);
BUG();
}
}
if (status)
{
/* unable to successfully issue / complete command, maybe because
* another resource (e.g. disk request buffers) is unavailable.
* stop removing items from the communications ring and try
* again later
*/
/*
printk ("do_block_io_op_domain domain:%d, pending_work: %x\n",
task->domain, pending_work);
*/
pending_work = pending_work | (1 << task->domain);
/*
printk ("do_block_io_op_domain domain:%d, pending_work: %x\n",
task->domain, pending_work);
*/
break;
}
}
blk_ring->tx_cons = loop;
return 0L;
}
int dispatch_debug_block_io (int index)
{
struct task_struct *task;
blk_ring_t *blk_ring = current->blk_ring_base;
char * buffer;
char output[1000];
int foobar = (unsigned long)blk_ring->tx_ring[index].block_number;
printk (KERN_ALERT "dispatch_debug_block_io %d\n", foobar);
buffer = phys_to_virt(blk_ring->tx_ring[index].buffer);
strcpy (buffer, "DEBUG\n");
task = current;
sprintf (buffer, "current %d\n", current->domain);
sprintf (buffer, "%s tx: prod: %d, cons: %d, size: %d\n", buffer,
blk_ring->tx_prod, blk_ring->tx_cons, blk_ring->tx_ring_size);
sprintf (buffer, "%s rx: prod: %d, cons: %d, size: %d\n", buffer,
blk_ring->rx_prod, blk_ring->rx_cons, blk_ring->rx_ring_size);
task = task->next_task;
while (task != current)
{
blk_ring = task->blk_ring_base;
sprintf (buffer, "%stask %d\n", buffer, task->domain);
if (blk_ring != NULL)
{
sprintf (buffer, "%s tx: prod: %d, cons: %d, size: %d\n",
buffer, blk_ring->tx_prod, blk_ring->tx_cons,
blk_ring->tx_ring_size);
sprintf (buffer, "%s rx: prod: %d, cons: %d, size: %d\n",
buffer, blk_ring->rx_prod, blk_ring->rx_cons,
blk_ring->rx_ring_size);
}
task = task->next_task;
}
dumpx(output, foobar);
sprintf (buffer, "%s%s\n", buffer, output);
return 0;
}
int dispatch_probe_block_io (int index)
{
blk_ring_t *blk_ring = current->blk_ring_base;
xen_disk_info_t *xdi;
xdi = phys_to_virt(blk_ring->tx_ring[index].buffer);
ide_probe_devices(xdi);
return 0;
}
int dispatch_rw_block_io (int index)
{
blk_ring_t *blk_ring = current->blk_ring_base;
struct buffer_head *bh;
struct request_queue *rq;
int operation;
blk_request_t *blk_request;
unsigned long flags;
/*
* check to make sure that the block request seems at least
* a bit legitimate
*/
if ((blk_ring->tx_ring[index].block_size & (0x200 - 1)) != 0)
{
printk(KERN_ALERT
" error: dodgy block size: %d\n",
blk_ring->tx_ring[index].block_size);
BUG();
}
if (XEN_BLK_DEBUG)
{
printk(XEN_BLK_DEBUG_LEVEL
" tx_cons: %d tx_prod %d index: %d op: %s, pri: %s\n",
blk_ring->tx_cons, blk_ring->tx_prod, index,
(blk_ring->tx_ring[index].operation == XEN_BLOCK_READ ? "read" : "write"),
(blk_ring->tx_ring[index].priority == XEN_BLOCK_SYNC ? "sync" : "async"));
}
{
char temp[100];
sprintf(temp, "issue buf: 0x%p, bh: 0x%p, blkno: 0x%lx",
blk_ring->tx_ring[index].buffer, bh,
(unsigned long)blk_ring->tx_ring[index].block_number);
printx(temp);
}
/* find an empty request slot */
spin_lock_irqsave(&free_queue_lock, flags);
if (list_empty(&free_queue))
{
/* printk (KERN_ALERT "dispatch_rw_block_io EMPTY FREE LIST!! %d\n", index); */
spin_unlock_irqrestore(&free_queue_lock, flags);
return 1;
}
blk_request = list_entry(free_queue.next, blk_request_t, queue);
list_del(&blk_request->queue);
spin_unlock_irqrestore(&free_queue_lock, flags);
/* place request on pending list */
spin_lock_irqsave(&pending_queue_lock, flags);
list_add_tail(&blk_request->queue, &pending_queue);
spin_unlock_irqrestore(&pending_queue_lock, flags);
/* we'll be doing this frequently, would a cache be appropriate? */
/* free in flush_blk_queue */
bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head),
GFP_KERNEL);
if (!bh)
{
printk(KERN_ALERT "ERROR: bh is null\n");
BUG();
}
/* set just the important bits of the buffer header */
memset (bh, 0, sizeof (struct buffer_head));
bh->b_blocknr = blk_ring->tx_ring[index].block_number; /* block number */
bh->b_size = blk_ring->tx_ring[index].block_size; /* block size */
bh->b_dev = blk_ring->tx_ring[index].device; /* device (B_FREE = free) */
bh->b_rsector = blk_ring->tx_ring[index].sector_number; /* sector number */
bh->b_data = phys_to_virt(blk_ring->tx_ring[index].buffer);
/* ptr to data blk */
bh->b_count.counter = 1; /* users using this block */
bh->b_xen_request = (void *)blk_request; /* save block request */
if (blk_ring->tx_ring[index].operation == XEN_BLOCK_WRITE)
{
bh->b_state = ((1 << BH_JBD) | /* buffer state bitmap */
(1 << BH_Mapped) |
(1 << BH_Req) |
(1 << BH_Dirty) |
(1 << BH_Uptodate));
operation = WRITE;
}
else
{
bh->b_state = (1 << BH_Mapped); /* buffer state bitmap */
operation = READ;
}
/* save meta data about request */
memcpy(&blk_request->request, /* NEED COPY_FROM_USER? */
&blk_ring->tx_ring[index], sizeof(blk_ring_entry_t));
blk_request->bh = bh;
blk_request->domain = current; /* save current domain */
/* dispatch single block request */
ll_rw_block(operation, 1, &bh); /* linux top half */
rq = blk_get_queue(bh->b_rdev);
generic_unplug_device(rq); /* linux bottom half */
return 0;
}
/*
* initialize_block_io
*
* initialize everything for block io
* called from arch/i386/setup.c::start_of_day
*/
void initialize_block_io ()
{
int loop;
INIT_LIST_HEAD(&free_queue);
INIT_LIST_HEAD(&pending_queue);
INIT_LIST_HEAD(&io_done_queue);
spin_lock_init(&free_queue_lock);
spin_lock_init(&pending_queue_lock);
spin_lock_init(&io_done_queue_lock);
for (loop = 0; loop < XEN_BLK_REQUEST_LIST_SIZE; loop++)
{
list_add_tail(&blk_request_list[loop].queue, &free_queue);
}
/*
* if bit i is true then domain i has work for us to do.
*/
pending_work = 0;
return;
}
#ifdef DEBUG
/*
* debug dump_queue
* arguments: queue head, name of queue
*/
void dump_queue(struct list_head *queue, char *name)
{
struct list_head *list;
int loop = 0;
printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue,
(unsigned long) queue->next, (unsigned long) queue->prev);
list_for_each (list, queue)
{
printk (" %s %d : %lx n: %lx, p: %lx\n", name, loop++,
(unsigned long)list,
(unsigned long)list->next, (unsigned long)list->prev);
}
}
void dump_queue_head(struct list_head *queue, char *name)
{
struct list_head *list;
int loop = 0;
printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue,
(unsigned long) queue->next, (unsigned long) queue->prev);
list_for_each (list, queue)
{
printk (" %d : %lx n: %lx, p: %lx\n", loop++,
(unsigned long)list,
(unsigned long)list->next, (unsigned long)list->prev);
if (loop >= 5) return;
}
}
#endif /* DEBUG */
#define debug_block_size 200000
#define debug_output_size 10
static int countx = 0;
static char * arrayx[debug_block_size];
static int outputx = 0;
void
printx (char * string)
{
char * s;
s = (char *) kmalloc(strlen(string), GFP_KERNEL);
strcpy (s, string);
arrayx[countx++] = s;
if (countx >= debug_block_size)
{
countx = 0;
printk (KERN_ALERT "printx wrap\n");
}
}
void
dumpx (char *buffer, int count)
{
int loop;
int start;
sprintf (buffer, "debug dump\n");
/*
for (loop = outputx;
loop < outputx + debug_output_size && loop < countx;
loop ++)
{
sprintf (buffer, "%s%02d:%s\n", buffer, loop, arrayx[loop]);
}
outputx = loop;
*/
if (count == 0 || count > countx)
{
start = 0;
}
else
{
start = countx - count;
}
printk (KERN_ALERT "DUMPX BUFFER\n");
for (loop = start; loop < countx; loop++)
{
printk (KERN_ALERT "%4d %s\n", loop, arrayx[loop]);
}
printk (KERN_ALERT "DUMPX bye bye\n");
}
+8
View File
@@ -0,0 +1,8 @@
include $(BASEDIR)/Rules.mk
default: $(OBJS)
$(LD) -r -o driver.o $(OBJS)
clean:
rm -f *.o *~ core
+113
View File
@@ -0,0 +1,113 @@
#include <asm-i386/io.h>
#define KEYBOARD_IRQ 1
#define KBD_STATUS_REG 0x64 /* Status register (R) */
#define KBD_CNTL_REG 0x64 /* Controller command register (W) */
#define KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
/* register status bits */
#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
#define KBD_STAT_PERR 0x80 /* Parity error */
#define kbd_read_input() inb(KBD_DATA_REG)
#define kbd_read_status() inb(KBD_STATUS_REG)
static void
dispatch_scancode (unsigned char scancode)
{
/*
* we could be a bit more clever here, but why?
* just add a jump to your debug routine for the appropriate character.
*/
switch (scancode)
{
case 0x01 : /* esc */
printk ("<esc>");
break;
case 0x9e : /* a */
printk ("a");
break;
case 0x9f : /* s */
printk ("s");
break;
case 0xae : /* c */
printk ("c");
break;
case 0xb0 : /* b */
printk ("b");
break;
case 0xbb : /* f1 */
printk ("<f1>");
break;
case 0xbc : /* f2 */
printk ("<f2>");
break;
case 0xbd : /* f3 */
printk ("<f3>");
break;
case 0xbe : /* f4 */
printk ("<f4>");
break;
case 0xbf : /* f5 */
/* xen_block_dump_state(); */
break;
default :
/* printk ("%x ", scancode); */
}
return;
}
/* regs should be struct pt_regs */
static void keyboard_interrupt(int irq, void *dev_id, void *regs)
{
unsigned char status = kbd_read_status();
unsigned int work = 10000;
while ((--work > 0) && (status & KBD_STAT_OBF))
{
unsigned char scancode;
scancode = kbd_read_input();
if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
{
if (status & KBD_STAT_MOUSE_OBF)
/* mouse event, ignore */;
else
dispatch_scancode (scancode);
}
status = kbd_read_status();
}
if (!work)
printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status);
return;
}
extern int request_irq(unsigned int,
void (*handler)(int, void *, struct pt_regs *),
unsigned long, const char *, void *);
void initialize_keyboard()
{
if(!request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL))
printk("initialize_keyboard: failed to alloc IRQ %d\n", KEYBOARD_IRQ);
return;
}
+93
View File
@@ -0,0 +1,93 @@
#include <asm-i386/io.h>
/* Register offsets */
#define NS16550_RBR 0x00 /* receive buffer */
#define NS16550_THR 0x00 /* transmit holding */
#define NS16550_IER 0x01 /* interrupt enable */
#define NS16550_IIR 0x02 /* interrupt identity */
#define NS16550_FCR 0x02 /* FIFO control */
#define NS16550_LCR 0x03 /* line control */
#define NS16550_MCR 0x04 /* MODEM control */
#define NS16550_LSR 0x05 /* line status */
#define NS16550_MSR 0x06 /* MODEM status */
#define NS16550_SCR 0x07 /* scratch */
#define NS16550_DDL 0x00 /* divisor latch (ls) ( DLAB=1) */
#define NS16550_DLM 0x01 /* divisor latch (ms) ( DLAB=1) */
/* Interrupt enable register */
#define NS16550_IER_ERDAI 0x01 /* rx data recv'd */
#define NS16550_IER_ETHREI 0x02 /* tx reg. empty */
#define NS16550_IER_ELSI 0x04 /* rx line status */
#define NS16550_IER_EMSI 0x08 /* MODEM status */
/* FIFO control register */
#define NS16550_FCR_ENABLE 0x01 /* enable FIFO */
#define NS16550_FCR_CLRX 0x02 /* clear Rx FIFO */
#define NS16550_FCR_CLTX 0x04 /* clear Tx FIFO */
#define NS16550_FCR_DMA 0x10 /* enter DMA mode */
#define NS16550_FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
#define NS16550_FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
#define NS16550_FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
#define NS16550_FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
/* MODEM control register */
#define NS16550_MCR_DTR 0x01 /* Data Terminal Ready */
#define NS16550_MCR_RTS 0x02 /* Request to Send */
#define NS16550_MCR_OUT1 0x04 /* OUT1: unused */
#define NS16550_MCR_OUT2 0x08 /* OUT2: interrupt mask */
#define NS16550_MCR_LOOP 0x10 /* Loop */
#define SERIAL_BASE 0x3f8 /* XXX SMH: horrible hardwired COM1 */
#define SERAIL_ECHO 0 /* XXX SMH: set to 1 for 'echo' on rx */
static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs)
{
int c;
/* XXX SMH: should probably check this is an RX interrupt :-) */
/* clear the interrupt by reading the character */
c = inb(SERIAL_BASE + NS16550_RBR );
if (c==0x04) {
/* This is 'debug me please' => just dump info and halt machine */
printk("serial_rx_int: got EOT => halting machine.\n");
printk("<not actually halting for now>\n");
}
#ifdef SERIAL_ECHO
printk("%c", c);
#endif
return;
}
extern int request_irq(unsigned int,
void (*handler)(int, void *, struct pt_regs *),
unsigned long, const char *, void *);
void initialize_serial()
{
int fifo = 1; /* must be a ns16550a at least, surely? */
if(fifo) {
/* Clear FIFOs, enable, trigger at 1 byte */
outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
NS16550_FCR_CLRX | NS16550_FCR_CLTX, SERIAL_BASE+NS16550_FCR);
}
outb(NS16550_MCR_OUT2, SERIAL_BASE + NS16550_MCR); /* Modem control */
outb(NS16550_IER_ERDAI, SERIAL_BASE + NS16550_IER ); /* Setup interrupts */
/* XXX SMH: this is a hack; probably is IRQ4 but grab both anyway */
if(!request_irq(4, serial_rx_int, 0, "serial", 0x1234))
printk("initialize_serial: failed to get IRQ4 :-(\n");
if(!request_irq(3, serial_rx_int, 0, "serial", 0x5678))
printk("initialize_serial: failed to get IRQ3 :-(\n");
return;
}
File diff suppressed because it is too large. Load diff
@@ -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
@@ -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);
@@ -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);
@@ -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
@@ -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;
}
@@ -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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &sect);
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, &current_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, &current_minor);
}
put_dev_sector(sect);
return 1;
}
+416
View File
@@ -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 */
@@ -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
+871
View File
@@ -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.");
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.