1/*
2 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1988 University of Utah.
30 * Copyright (c) 1990, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * the Systems Programming Group of the University of Utah Computer
35 * Science Department.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 *    notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 *    notice, this list of conditions and the following disclaimer in the
44 *    documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 *    must display the following acknowledgement:
47 *	This product includes software developed by the University of
48 *	California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 *    may be used to endorse or promote products derived from this software
51 *    without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * from: Utah Hdr: vn.c 1.13 94/04/02
66 *
67 *	from: @(#)vn.c	8.6 (Berkeley) 4/1/94
68 * $FreeBSD: src/sys/dev/vn/vn.c,v 1.105.2.4 2001/11/18 07:11:00 dillon Exp $
69 */
70
71/*
72 * RAM disk driver.
73 *
74 * Block interface to a ramdisk.
75 *
76 */
77
78#include <sys/param.h>
79#include <sys/kernel.h>
80#include <sys/mount.h>
81#include <sys/namei.h>
82#include <sys/proc.h>
83#include <sys/buf.h>
84#include <sys/malloc.h>
85#include <sys/mount.h>
86#include <sys/fcntl.h>
87#include <sys/conf.h>
88#include <sys/disk.h>
89#include <sys/stat.h>
90#include <sys/vm.h>
91#include <sys/uio_internal.h>
92#include <libkern/libkern.h>
93
94#include <vm/pmap.h>
95#include <vm/vm_pager.h>
96#include <mach/memory_object_types.h>
97#include <kern/debug.h>
98
99#include <miscfs/devfs/devfs.h>
100
101
102void 		mdevinit(int the_cnt);
103
104static open_close_fcn_t	mdevopen;
105static open_close_fcn_t	mdevclose;
106static psize_fcn_t		mdevsize;
107static strategy_fcn_t	mdevstrategy;
108static int				mdevbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
109static int				mdevcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p);
110static int 				mdevrw(dev_t dev, struct uio *uio, int ioflag);
111#ifdef CONFIG_MEMDEV_INSECURE
112static char *			nonspace(char *pos, char *end);
113static char *			getspace(char *pos, char *end);
114static char *			cvtnum(char *pos, char *end, unsigned int *num);
115#endif /* CONFIG_MEMDEV_INSECURE */
116
117extern void		bcopy_phys(addr64_t from, addr64_t to, vm_size_t bytes);
118extern void		mapping_set_mod(ppnum_t pn);
119extern ppnum_t 	pmap_find_phys(pmap_t pmap, addr64_t va);
120
121
122/*
123 * cdevsw
124 *	D_DISK		we want to look like a disk
125 *	D_CANFREE	We support B_FREEBUF
126 */
127
128static struct bdevsw mdevbdevsw = {
129	/* open */	mdevopen,
130	/* close */	mdevclose,
131	/* strategy */	mdevstrategy,
132	/* ioctl */	mdevbioctl,
133	/* dump */	eno_dump,
134	/* psize */	mdevsize,
135	/* flags */	D_DISK,
136};
137
138static struct cdevsw mdevcdevsw = {
139	/* open */	mdevopen,
140	/* close */	mdevclose,
141	/* read */	mdevrw,
142	/* write */	mdevrw,
143	/* ioctl */	mdevcioctl,
144	/* stop */	eno_stop,
145	/* reset */	eno_reset,
146	/* ttys */	NULL,
147	/* select */	eno_select,
148	/* mmap */	eno_mmap,
149	/* strategy */	eno_strat,
150	/* getc */	eno_getc,
151	/* putc */	eno_putc,
152	/* flags */	D_DISK,
153};
154
155struct mdev {
156	vm_offset_t	mdBase;		/* file size in bytes */
157	uint32_t	mdSize;		/* file size in bytes */
158	int			mdFlags;	/* flags */
159	int			mdSecsize;	/* sector size */
160	int			mdBDev;		/* Block device number */
161	int			mdCDev;		/* Character device number */
162	void *		mdbdevb;
163	void *		mdcdevb;
164} mdev[16];
165
166/* mdFlags */
167#define mdInited	0x01	/* This device defined */
168#define	mdRO		0x02	/* This device is read-only */
169#define	mdPhys		0x04	/* This device is in physical memory */
170
171int mdevBMajor = -1;
172int mdevCMajor = -1;
173
174static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p, int is_char);
175dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys);
176dev_t mdevlookup(int devid);
177void mdevremoveall(void);
178
179static	int mdevclose(__unused dev_t dev, __unused int flags,
180					  __unused int devtype, __unused struct proc *p) {
181
182	return (0);
183}
184
185static	int mdevopen(dev_t dev, int flags, __unused int devtype, __unused struct proc *p) {
186
187	int devid;
188
189	devid = minor(dev);									/* Get minor device number */
190
191	if (devid > 16) return (ENXIO);						/* Not valid */
192
193	if ((flags & FWRITE) && (mdev[devid].mdFlags & mdRO)) return (EACCES);	/* Currently mounted RO */
194
195	return(0);
196}
197
198static int mdevrw(dev_t dev, struct uio *uio, __unused int ioflag) {
199	int 			status;
200	addr64_t		mdata;
201	int 			devid;
202	enum uio_seg 	saveflag;
203
204	devid = minor(dev);									/* Get minor device number */
205
206	if (devid > 16) return (ENXIO);						/* Not valid */
207	if (!(mdev[devid].mdFlags & mdInited))  return (ENXIO);	/* Have we actually been defined yet? */
208
209	mdata = ((addr64_t)mdev[devid].mdBase << 12) + uio->uio_offset;	/* Point to the area in "file" */
210
211	saveflag = uio->uio_segflg;							/* Remember what the request is */
212#if LP64_DEBUG
213	if (IS_VALID_UIO_SEGFLG(uio->uio_segflg) == 0) {
214	  panic("mdevrw - invalid uio_segflg\n");
215	}
216#endif /* LP64_DEBUG */
217	/* Make sure we are moving from physical ram if physical device */
218	if (mdev[devid].mdFlags & mdPhys) {
219		if (uio->uio_segflg == UIO_USERSPACE64)
220			uio->uio_segflg = UIO_PHYS_USERSPACE64;
221		else if (uio->uio_segflg == UIO_USERSPACE32)
222			uio->uio_segflg = UIO_PHYS_USERSPACE32;
223		else
224			uio->uio_segflg = UIO_PHYS_USERSPACE;
225	}
226	status = uiomove64(mdata, uio_resid(uio), uio);		/* Move the data */
227	uio->uio_segflg = saveflag;							/* Restore the flag */
228
229	return (status);
230}
231
232static void mdevstrategy(struct buf *bp) {
233	unsigned int left, lop, csize;
234	vm_offset_t vaddr, blkoff;
235	int devid;
236	addr64_t paddr, fvaddr;
237	ppnum_t pp;
238
239	devid = minor(buf_device(bp));							/* Get minor device number */
240
241	if ((mdev[devid].mdFlags & mdInited) == 0) {		/* Have we actually been defined yet? */
242	        buf_seterror(bp, ENXIO);
243		buf_biodone(bp);
244		return;
245	}
246
247	buf_setresid(bp, buf_count(bp));						/* Set byte count */
248
249	blkoff = buf_blkno(bp) * mdev[devid].mdSecsize;		/* Get offset into file */
250
251/*
252 *	Note that reading past end is an error, but reading at end is an EOF.  For these
253 *	we just return with resid == count.
254 */
255
256	if (blkoff >= (mdev[devid].mdSize << 12)) {			/* Are they trying to read/write at/after end? */
257		if(blkoff != (mdev[devid].mdSize << 12)) {		/* Are we trying to read after EOF? */
258		        buf_seterror(bp, EINVAL);						/* Yeah, this is an error */
259		}
260		buf_biodone(bp);								/* Return */
261		return;
262	}
263
264	if ((blkoff + buf_count(bp)) > (mdev[devid].mdSize << 12)) {		/* Will this read go past end? */
265		buf_setcount(bp, ((mdev[devid].mdSize << 12) - blkoff));	/* Yes, trim to max */
266	}
267	/*
268	 * make sure the buffer's data area is
269	 * accessible
270	 */
271	if (buf_map(bp, (caddr_t *)&vaddr))
272	        panic("ramstrategy: buf_map failed\n");
273
274	fvaddr = (mdev[devid].mdBase << 12) + blkoff;		/* Point to offset into ram disk */
275
276	if (buf_flags(bp) & B_READ) {					/* Is this a read? */
277		if(!(mdev[devid].mdFlags & mdPhys)) {			/* Physical mapped disk? */
278			bcopy((void *)((uintptr_t)fvaddr),
279				(void *)vaddr, (size_t)buf_count(bp));	/* This is virtual, just get the data */
280		}
281		else {
282			left = buf_count(bp);						/* Init the amount left to copy */
283			while(left) {								/* Go until it is all copied */
284
285				lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095)));	/* Get smallest amount left on sink and source */
286				csize = min(lop, left);					/* Don't move more than we need to */
287
288				pp = pmap_find_phys(kernel_pmap, (addr64_t)((unsigned int)vaddr));	/* Get the sink physical address */
289				if(!pp) {								/* Not found, what gives? */
290					panic("mdevstrategy: sink address %016llX not mapped\n", (addr64_t)((unsigned int)vaddr));
291				}
292				paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095));	/* Get actual address */
293				bcopy_phys(fvaddr, paddr, csize);		/* Copy this on in */
294				mapping_set_mod(paddr >> 12);			/* Make sure we know that it is modified */
295
296				left = left - csize;					/* Calculate what is left */
297				vaddr = vaddr + csize;					/* Move to next sink address */
298				fvaddr = fvaddr + csize;				/* Bump to next physical address */
299			}
300		}
301	}
302	else {												/* This is a write */
303		if(!(mdev[devid].mdFlags & mdPhys)) {			/* Physical mapped disk? */
304			bcopy((void *)vaddr, (void *)((uintptr_t)fvaddr),
305				(size_t)buf_count(bp));		/* This is virtual, just put the data */
306		}
307		else {
308			left = buf_count(bp);						/* Init the amount left to copy */
309			while(left) {								/* Go until it is all copied */
310
311				lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095)));	/* Get smallest amount left on sink and source */
312				csize = min(lop, left);					/* Don't move more than we need to */
313
314				pp = pmap_find_phys(kernel_pmap, (addr64_t)((unsigned int)vaddr));	/* Get the source physical address */
315				if(!pp) {								/* Not found, what gives? */
316					panic("mdevstrategy: source address %016llX not mapped\n", (addr64_t)((unsigned int)vaddr));
317				}
318				paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095));	/* Get actual address */
319
320				bcopy_phys(paddr, fvaddr, csize);		/* Move this on out */
321
322				left = left - csize;					/* Calculate what is left */
323				vaddr = vaddr + csize;					/* Move to next sink address */
324				fvaddr = fvaddr + csize;				/* Bump to next physical address */
325			}
326		}
327	}
328	/*
329	 * buf_unmap takes care of all the cases
330	 * it will unmap the buffer from kernel
331	 * virtual space if that was the state
332	 * when we mapped it.
333	 */
334	buf_unmap(bp);
335
336	buf_setresid(bp, 0);									/* Nothing more to do */
337	buf_biodone(bp);									/* Say we've finished */
338}
339
340static int mdevbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) {
341	return (mdevioctl(dev, cmd, data, flag, p, 0));
342}
343
344static int mdevcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) {
345	return (mdevioctl(dev, cmd, data, flag, p, 1));
346}
347
348static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, __unused int flag,
349					 struct proc *p, int is_char) {
350	int error;
351	u_long *f;
352	u_int64_t *o;
353	int devid;
354
355	devid = minor(dev);									/* Get minor device number */
356
357	if (devid > 16) return (ENXIO);						/* Not valid */
358
359	error = proc_suser(p);			/* Are we superman? */
360	if (error) return (error);							/* Nope... */
361
362	f = (u_long*)data;
363	o = (u_int64_t *)data;
364
365	switch (cmd) {
366
367		case DKIOCGETMAXBLOCKCOUNTREAD:
368			*o = 32;
369			break;
370
371		case DKIOCGETMAXBLOCKCOUNTWRITE:
372			*o = 32;
373			break;
374
375		case DKIOCGETMAXSEGMENTCOUNTREAD:
376			*o = 32;
377			break;
378
379		case DKIOCGETMAXSEGMENTCOUNTWRITE:
380			*o = 32;
381			break;
382
383		case DKIOCGETBLOCKSIZE:
384			*f = mdev[devid].mdSecsize;
385			break;
386
387		case DKIOCSETBLOCKSIZE:
388			if (is_char) return (ENODEV);				/* We can only do this for a block */
389
390			if (*f < DEV_BSIZE) return (EINVAL);		/* Too short? */
391
392			mdev[devid].mdSecsize = *f;					/* set the new block size */
393			break;
394
395		case DKIOCISWRITABLE:
396			*f = 1;
397			break;
398
399		case DKIOCGETBLOCKCOUNT32:
400			if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO);
401			*f = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize;
402			break;
403
404		case DKIOCGETBLOCKCOUNT:
405			if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO);
406			*o = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize;
407			break;
408
409		default:
410			error = ENOTTY;
411			break;
412	}
413	return(error);
414}
415
416
417static	int mdevsize(dev_t dev) {
418
419	int devid;
420
421	devid = minor(dev);									/* Get minor device number */
422	if (devid > 16) return (ENXIO);						/* Not valid */
423
424	if ((mdev[devid].mdFlags & mdInited) == 0) return(-1);		/* Not inited yet */
425
426	return(mdev[devid].mdSecsize);
427}
428
429#include <pexpert/pexpert.h>
430
431void mdevinit(__unused int the_cnt) {
432
433#ifdef CONFIG_MEMDEV_INSECURE
434
435	int devid, phys;
436	ppnum_t base;
437	unsigned int size;
438	char *ba, *lp;
439	dev_t dev;
440
441	ba = PE_boot_args();								/* Get the boot arguments */
442	lp = ba + 256;										/* Point to the end */
443
444	while(1) {											/* Step through, looking for our keywords */
445		phys = 0;										/* Assume virtual memory device */
446		ba = nonspace(ba, lp);							/* Find non-space */
447		if(ba >= lp) return;							/* We are done if no more... */
448		if(((ba[0] != 'v') && (ba[0] != 'p'))
449		  || (ba[1] != 'm') || (ba[2] != 'd') || (ba[4] != '=')
450		  || (ba[3] < '0') || (ba[3] > 'f')
451		  || ((ba[3] > '9') && (ba[3] < 'a'))) {		/* Is this of form "vmdx=" or "pmdx=" where x is hex digit? */
452
453			ba = getspace(ba, lp);						/* Find next white space or end */
454			continue;									/* Start looking for the next one */
455		}
456
457		if(ba[0] == 'p') phys = 1;						/* Set physical memory disk */
458
459		devid = ba[3] & 0xF;							/* Assume digit */
460		if(ba[3] > '9') devid += 9;						/* Adjust for hex digits */
461
462		ba = &ba[5];									/* Step past keyword */
463		ba = cvtnum(ba, lp, &base);						/* Convert base of memory disk */
464		if(ba >= lp) return;							/* Malformed one at the end, leave */
465		if(ba[0] != '.') continue;						/* If not length separater, try next... */
466		if(base & 0xFFF) continue;						/* Only allow page aligned stuff */
467
468		ba++;											/* Step past '.' */
469		ba = cvtnum(ba, lp, &size);						/* Try to convert it */
470		if(!size || (size & 0xFFF)) continue;			/* Allow only non-zer page size multiples */
471		if(ba < lp) {									/* If we are not at end, check end character */
472			if((ba[0] != ' ') && (ba[0] != 0)) continue;	/* End must be null or space */
473		}
474
475		dev = mdevadd(devid, base >> 12, size >> 12, phys);	/* Go add the device */
476	}
477
478#endif /* CONFIG_MEMDEV_INSECURE */
479	return;
480
481}
482
483#ifdef CONFIG_MEMDEV_INSECURE
484char *nonspace(char *pos, char *end) {					/* Find next non-space in string */
485
486	if(pos >= end) return end;							/* Don't go past end */
487	if(pos[0] == 0) return end;							/* If at null, make end */
488
489	while(1) {											/* Keep going */
490		if(pos[0] != ' ') return pos;					/* Leave if we found one */
491		pos++;											/* Stop */
492		if(pos >= end) return end;						/* Quit if we run off end */
493	}
494}
495
496char *getspace(char *pos, char *end) {					/* Find next non-space in string */
497
498	while(1) {											/* Keep going */
499		if(pos >= end) return end;						/* Don't go past end */
500		if(pos[0] == 0) return end;						/* Leave if we hit null */
501		if(pos[0] == ' ') return pos;					/* Leave if we found one */
502		pos++;											/* Stop */
503	}
504}
505
506char *cvtnum(char *pos, char *end, unsigned int *num) {		/* Convert to a number */
507
508	int rad, dig;
509
510	*num = 0;											/* Set answer to 0 to start */
511	rad = 10;
512
513	if(pos >= end) return end;							/* Don't go past end */
514	if(pos[0] == 0) return end;							/* If at null, make end */
515
516	if(pos[0] == '0' && ((pos[1] == 'x') || (pos[1] == 'x'))) {	/* A hex constant? */
517		rad = 16;
518		pos += 2;										/* Point to the number */
519	}
520
521	while(1) {											/* Convert it */
522
523		if(pos >= end) return end;						/* Don't go past end */
524		if(pos[0] == 0) return end;						/* If at null, make end */
525		if(pos[0] < '0') return pos;					/* Leave if non-digit */
526		dig = pos[0] & 0xF;								/* Extract digit */
527		if(pos[0] > '9') {								/* Is it bigger than 9? */
528			if(rad == 10) return pos;					/* Leave if not base 10 */
529			if(!(((pos[0] >= 'A') && (pos[0] <= 'F'))
530			  || ((pos[0] >= 'a') && (pos[0] <= 'f')))) return pos;	/* Leave if bogus char */
531			 dig = dig + 9;								/* Adjust for character */
532		}
533		*num = (*num * rad) + dig;						/* Accumulate the number */
534		pos++;											/* Step on */
535	}
536}
537#endif /* CONFIG_MEMDEV_INSECURE */
538
539dev_t mdevadd(int devid, ppnum_t base, unsigned int size, int phys) {
540
541	int i;
542
543	if(devid < 0) {
544
545		devid = -1;
546		for(i = 0; i < 16; i++) {						/* Search all known memory devices */
547			if(!(mdev[i].mdFlags & mdInited)) {			/* Is this a free one? */
548				if(devid < 0)devid = i;					/* Remember first free one */
549				continue;								/* Skip check */
550			}
551			if(!(((base + size -1 ) < mdev[i].mdBase) || ((mdev[i].mdBase + mdev[i].mdSize - 1) < base))) {	/* Is there any overlap? */
552				panic("mdevadd: attempt to add overlapping memory device at %08X-%08X\n", mdev[i].mdBase, mdev[i].mdBase + mdev[i].mdSize - 1);
553			}
554		}
555		if(devid < 0) {									/* Do we have free slots? */
556			panic("mdevadd: attempt to add more than 16 memory devices\n");
557		}
558	}
559	else {
560		if(devid >= 16) {								/* Giving us something bogus? */
561			panic("mdevadd: attempt to explicitly add a bogus memory device: %08X\n", devid);
562		}
563		if(mdev[devid].mdFlags &mdInited) {				/* Already there? */
564			panic("mdevadd: attempt to explicitly add a previously defined memory device: %08X\n", devid);
565		}
566	}
567
568	if(mdevBMajor < 0) {								/* Have we gotten a major number yet? */
569		mdevBMajor = bdevsw_add(-1, &mdevbdevsw);		/* Add to the table and figure out a major number */
570		if (mdevBMajor < 0) {
571			printf("mdevadd: error - bdevsw_add() returned %d\n", mdevBMajor);
572			return -1;
573		}
574	}
575
576	if(mdevCMajor < 0) {								/* Have we gotten a major number yet? */
577		mdevCMajor = cdevsw_add_with_bdev(-1, &mdevcdevsw, mdevBMajor);		/* Add to the table and figure out a major number */
578		if (mdevCMajor < 0) {
579			printf("ramdevice_init: error - cdevsw_add() returned %d\n", mdevCMajor);
580			return -1;
581		}
582	}
583
584	mdev[devid].mdBDev = makedev(mdevBMajor, devid);	/* Get the device number */
585	mdev[devid].mdbdevb = devfs_make_node(mdev[devid].mdBDev, DEVFS_BLOCK,	/* Make the node */
586						  UID_ROOT, GID_OPERATOR,
587						  0600, "md%d", devid);
588	if (mdev[devid].mdbdevb == NULL) {					/* Did we make one? */
589		printf("mdevadd: devfs_make_node for block failed!\n");
590		return -1;										/* Nope... */
591	}
592
593	mdev[devid].mdCDev = makedev(mdevCMajor, devid);	/* Get the device number */
594	mdev[devid].mdcdevb = devfs_make_node(mdev[devid].mdCDev, DEVFS_CHAR,		/* Make the node */
595						  UID_ROOT, GID_OPERATOR,
596						  0600, "rmd%d", devid);
597	if (mdev[devid].mdcdevb == NULL) {					/* Did we make one? */
598		printf("mdevadd: devfs_make_node for character failed!\n");
599		return -1;										/* Nope... */
600	}
601
602	mdev[devid].mdBase = base;							/* Set the base address of ram disk */
603	mdev[devid].mdSize = size;							/* Set the length of the ram disk */
604	mdev[devid].mdSecsize = DEV_BSIZE;					/* Set starting block size */
605	if(phys) mdev[devid].mdFlags |= mdPhys;				/* Show that we are in physical memory */
606	mdev[devid].mdFlags |= mdInited;					/* Show we are all set up */
607	printf("Added memory device md%x/rmd%x (%08X/%08X) at %08X for %08X\n",
608		devid, devid, mdev[devid].mdBDev, mdev[devid].mdCDev, base << 12, size << 12);
609	return mdev[devid].mdBDev;
610}
611
612
613dev_t mdevlookup(int devid) {
614
615	if((devid < 0) || (devid > 15)) return -1;			/* Filter any bogus requests */
616	if(!(mdev[devid].mdFlags & mdInited)) return -1;	/* This one hasn't been defined */
617	return mdev[devid].mdBDev;							/* Return the device number */
618}
619
620void mdevremoveall(void) {
621
622	int i;
623
624	for(i = 0; i < 16; i++) {
625		if(!(mdev[i].mdFlags & mdInited)) continue;	/* Ignore unused mdevs */
626
627		devfs_remove(mdev[i].mdbdevb);			/* Remove the block device */
628		devfs_remove(mdev[i].mdcdevb);			/* Remove the character device */
629
630		mdev[i].mdBase = 0;				/* Clear the mdev's storage */
631		mdev[i].mdSize = 0;
632		mdev[i].mdSecsize = 0;
633		mdev[i].mdFlags = 0;
634		mdev[i].mdBDev = 0;
635		mdev[i].mdCDev = 0;
636		mdev[i].mdbdevb = 0;
637		mdev[i].mdcdevb = 0;
638	}
639}
640