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
112#ifdef CONFIG_MEMDEV_INSECURE
113
114static char *			nonspace(char *pos, char *end);
115static char *			getspace(char *pos, char *end);
116static char *			cvtnum(char *pos, char *end, uint64_t *num);
117
118#endif /* CONFIG_MEMDEV_INSECURE */
119
120extern void		bcopy_phys(addr64_t from, addr64_t to, vm_size_t bytes);
121extern void		mapping_set_mod(ppnum_t pn);
122extern ppnum_t 	pmap_find_phys(pmap_t pmap, addr64_t va);
123
124
125/*
126 * cdevsw
127 *	D_DISK		we want to look like a disk
128 *	D_CANFREE	We support B_FREEBUF
129 */
130
131static struct bdevsw mdevbdevsw = {
132	/* open */	mdevopen,
133	/* close */	mdevclose,
134	/* strategy */	mdevstrategy,
135	/* ioctl */	mdevbioctl,
136	/* dump */	eno_dump,
137	/* psize */	mdevsize,
138	/* flags */	D_DISK,
139};
140
141static struct cdevsw mdevcdevsw = {
142	/* open */	mdevopen,
143	/* close */	mdevclose,
144	/* read */	mdevrw,
145	/* write */	mdevrw,
146	/* ioctl */	mdevcioctl,
147	/* stop */	eno_stop,
148	/* reset */	eno_reset,
149	/* ttys */	NULL,
150	/* select */	eno_select,
151	/* mmap */	eno_mmap,
152	/* strategy */	eno_strat,
153	/* getc */	eno_getc,
154	/* putc */	eno_putc,
155	/* flags */	D_DISK,
156};
157
158struct mdev {
159	uint64_t	mdBase;		/* file size in bytes */
160	uint32_t	mdSize;		/* file size in bytes */
161	int			mdFlags;	/* flags */
162	int			mdSecsize;	/* sector size */
163	int			mdBDev;		/* Block device number */
164	int			mdCDev;		/* Character device number */
165	void *		mdbdevb;
166	void *		mdcdevb;
167} mdev[16];
168
169/* mdFlags */
170#define mdInited	0x01	/* This device defined */
171#define	mdRO		0x02	/* This device is read-only */
172#define	mdPhys		0x04	/* This device is in physical memory */
173
174int mdevBMajor = -1;
175int mdevCMajor = -1;
176
177static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p, int is_char);
178dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys);
179dev_t mdevlookup(int devid);
180void mdevremoveall(void);
181
182static	int mdevclose(__unused dev_t dev, __unused int flags,
183					  __unused int devtype, __unused struct proc *p) {
184
185	return (0);
186}
187
188static	int mdevopen(dev_t dev, int flags, __unused int devtype, __unused struct proc *p) {
189
190	int devid;
191
192	devid = minor(dev);									/* Get minor device number */
193
194	if (devid > 16) return (ENXIO);						/* Not valid */
195
196	if ((flags & FWRITE) && (mdev[devid].mdFlags & mdRO)) return (EACCES);	/* Currently mounted RO */
197
198	return(0);
199}
200
201static int mdevrw(dev_t dev, struct uio *uio, __unused int ioflag) {
202	int 			status;
203	addr64_t		mdata;
204	int 			devid;
205	enum uio_seg 	saveflag;
206
207	devid = minor(dev);									/* Get minor device number */
208
209	if (devid > 16) return (ENXIO);						/* Not valid */
210	if (!(mdev[devid].mdFlags & mdInited))  return (ENXIO);	/* Have we actually been defined yet? */
211
212	mdata = ((addr64_t)mdev[devid].mdBase << 12) + uio->uio_offset;	/* Point to the area in "file" */
213
214	saveflag = uio->uio_segflg;							/* Remember what the request is */
215#if LP64_DEBUG
216	if (UIO_IS_USER_SPACE(uio) == 0 && UIO_IS_SYS_SPACE(uio) == 0) {
217	  panic("mdevrw - invalid uio_segflg\n");
218	}
219#endif /* LP64_DEBUG */
220	/* Make sure we are moving from physical ram if physical device */
221	if (mdev[devid].mdFlags & mdPhys) {
222		if (uio->uio_segflg == UIO_USERSPACE64)
223			uio->uio_segflg = UIO_PHYS_USERSPACE64;
224		else if (uio->uio_segflg == UIO_USERSPACE32)
225			uio->uio_segflg = UIO_PHYS_USERSPACE32;
226		else
227			uio->uio_segflg = UIO_PHYS_USERSPACE;
228	}
229	status = uiomove64(mdata, uio_resid(uio), uio);		/* Move the data */
230	uio->uio_segflg = saveflag;							/* Restore the flag */
231
232	return (status);
233}
234
235static void mdevstrategy(struct buf *bp) {
236	unsigned int left, lop, csize;
237	vm_offset_t vaddr, blkoff;
238	int devid;
239	addr64_t paddr, fvaddr;
240	ppnum_t pp;
241
242	devid = minor(buf_device(bp));							/* Get minor device number */
243
244	if ((mdev[devid].mdFlags & mdInited) == 0) {		/* Have we actually been defined yet? */
245	        buf_seterror(bp, ENXIO);
246		buf_biodone(bp);
247		return;
248	}
249
250	buf_setresid(bp, buf_count(bp));						/* Set byte count */
251
252	blkoff = buf_blkno(bp) * mdev[devid].mdSecsize;		/* Get offset into file */
253
254/*
255 *	Note that reading past end is an error, but reading at end is an EOF.  For these
256 *	we just return with resid == count.
257 */
258
259	if (blkoff >= (mdev[devid].mdSize << 12)) {			/* Are they trying to read/write at/after end? */
260		if(blkoff != (mdev[devid].mdSize << 12)) {		/* Are we trying to read after EOF? */
261		        buf_seterror(bp, EINVAL);						/* Yeah, this is an error */
262		}
263		buf_biodone(bp);								/* Return */
264		return;
265	}
266
267	if ((blkoff + buf_count(bp)) > (mdev[devid].mdSize << 12)) {		/* Will this read go past end? */
268		buf_setcount(bp, ((mdev[devid].mdSize << 12) - blkoff));	/* Yes, trim to max */
269	}
270	/*
271	 * make sure the buffer's data area is
272	 * accessible
273	 */
274	if (buf_map(bp, (caddr_t *)&vaddr))
275	        panic("ramstrategy: buf_map failed\n");
276
277	fvaddr = (mdev[devid].mdBase << 12) + blkoff;		/* Point to offset into ram disk */
278
279	if (buf_flags(bp) & B_READ) {					/* Is this a read? */
280		if(!(mdev[devid].mdFlags & mdPhys)) {			/* Physical mapped disk? */
281			bcopy((void *)((uintptr_t)fvaddr),
282				(void *)vaddr, (size_t)buf_count(bp));	/* This is virtual, just get the data */
283		}
284		else {
285			left = buf_count(bp);						/* Init the amount left to copy */
286			while(left) {								/* Go until it is all copied */
287
288				lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095)));	/* Get smallest amount left on sink and source */
289				csize = min(lop, left);					/* Don't move more than we need to */
290
291				pp = pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)vaddr));	/* Get the sink physical address */
292				if(!pp) {								/* Not found, what gives? */
293					panic("mdevstrategy: sink address %016llX not mapped\n", (addr64_t)((uintptr_t)vaddr));
294				}
295				paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095));	/* Get actual address */
296				bcopy_phys(fvaddr, paddr, csize);		/* Copy this on in */
297				mapping_set_mod(paddr >> 12);			/* Make sure we know that it is modified */
298
299				left = left - csize;					/* Calculate what is left */
300				vaddr = vaddr + csize;					/* Move to next sink address */
301				fvaddr = fvaddr + csize;				/* Bump to next physical address */
302			}
303		}
304	}
305	else {												/* This is a write */
306		if(!(mdev[devid].mdFlags & mdPhys)) {			/* Physical mapped disk? */
307			bcopy((void *)vaddr, (void *)((uintptr_t)fvaddr),
308				(size_t)buf_count(bp));		/* This is virtual, just put the data */
309		}
310		else {
311			left = buf_count(bp);						/* Init the amount left to copy */
312			while(left) {								/* Go until it is all copied */
313
314				lop = min((4096 - (vaddr & 4095)), (4096 - (fvaddr & 4095)));	/* Get smallest amount left on sink and source */
315				csize = min(lop, left);					/* Don't move more than we need to */
316
317				pp = pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)vaddr));	/* Get the source physical address */
318				if(!pp) {								/* Not found, what gives? */
319					panic("mdevstrategy: source address %016llX not mapped\n", (addr64_t)((uintptr_t)vaddr));
320				}
321				paddr = (addr64_t)(((addr64_t)pp << 12) | (addr64_t)(vaddr & 4095));	/* Get actual address */
322
323				bcopy_phys(paddr, fvaddr, csize);		/* Move this on out */
324
325				left = left - csize;					/* Calculate what is left */
326				vaddr = vaddr + csize;					/* Move to next sink address */
327				fvaddr = fvaddr + csize;				/* Bump to next physical address */
328			}
329		}
330	}
331	/*
332	 * buf_unmap takes care of all the cases
333	 * it will unmap the buffer from kernel
334	 * virtual space if that was the state
335	 * when we mapped it.
336	 */
337	buf_unmap(bp);
338
339	buf_setresid(bp, 0);									/* Nothing more to do */
340	buf_biodone(bp);									/* Say we've finished */
341}
342
343static int mdevbioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) {
344	return (mdevioctl(dev, cmd, data, flag, p, 0));
345}
346
347static int mdevcioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) {
348	return (mdevioctl(dev, cmd, data, flag, p, 1));
349}
350
351static int mdevioctl(dev_t dev, u_long cmd, caddr_t data, __unused int flag,
352					 struct proc *p, int is_char) {
353	int error;
354	u_int32_t *f;
355	u_int64_t *o;
356	int devid;
357	dk_memdev_info_t * memdev_info;
358
359	devid = minor(dev);									/* Get minor device number */
360
361	if (devid > 16) return (ENXIO);						/* Not valid */
362
363	error = proc_suser(p);			/* Are we superman? */
364	if (error) return (error);							/* Nope... */
365
366	f = (u_int32_t*)data;
367	o = (u_int64_t *)data;
368	memdev_info = (dk_memdev_info_t *) data;
369
370	switch (cmd) {
371
372		case DKIOCGETMAXBLOCKCOUNTREAD:
373			*o = 32;
374			break;
375
376		case DKIOCGETMAXBLOCKCOUNTWRITE:
377			*o = 32;
378			break;
379
380		case DKIOCGETMAXSEGMENTCOUNTREAD:
381			*o = 32;
382			break;
383
384		case DKIOCGETMAXSEGMENTCOUNTWRITE:
385			*o = 32;
386			break;
387
388		case DKIOCGETBLOCKSIZE:
389			*f = mdev[devid].mdSecsize;
390			break;
391
392		case DKIOCSETBLOCKSIZE:
393			if (is_char) return (ENODEV);				/* We can only do this for a block */
394
395			if (*f < DEV_BSIZE) return (EINVAL);		/* Too short? */
396
397			mdev[devid].mdSecsize = *f;					/* set the new block size */
398			break;
399
400		case DKIOCISWRITABLE:
401			*f = 1;
402			break;
403
404		case DKIOCGETBLOCKCOUNT32:
405			if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO);
406			*f = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize;
407			break;
408
409		case DKIOCGETBLOCKCOUNT:
410			if(!(mdev[devid].mdFlags & mdInited)) return (ENXIO);
411			*o = ((mdev[devid].mdSize << 12) + mdev[devid].mdSecsize - 1) / mdev[devid].mdSecsize;
412			break;
413
414		/*
415		 * We're interested in the following bits of information:
416		 *   Are you a memory-backed device (always yes, in this case)?
417		 *   Physical memory (mdPhys)?
418		 *   What is your base page?
419		 *   What is your size?
420		 */
421		case DKIOCGETMEMDEVINFO:
422			if (!(mdev[devid].mdFlags & mdInited)) return (ENXIO);
423			memdev_info->mi_mdev = TRUE;
424			memdev_info->mi_phys = (mdev[devid].mdFlags & mdPhys) ? TRUE : FALSE;
425			memdev_info->mi_base = mdev[devid].mdBase;
426			memdev_info->mi_size = mdev[devid].mdSize;
427			break;
428
429		default:
430			error = ENOTTY;
431			break;
432	}
433	return(error);
434}
435
436
437static	int mdevsize(dev_t dev) {
438
439	int devid;
440
441	devid = minor(dev);									/* Get minor device number */
442	if (devid > 16) return (ENXIO);						/* Not valid */
443
444	if ((mdev[devid].mdFlags & mdInited) == 0) return(-1);		/* Not inited yet */
445
446	return(mdev[devid].mdSecsize);
447}
448
449#include <pexpert/pexpert.h>
450
451void mdevinit(__unused int the_cnt) {
452
453#ifdef CONFIG_MEMDEV_INSECURE
454
455	int devid, phys;
456	uint64_t base;
457	uint64_t size;
458	char *ba, *lp;
459	dev_t dev;
460
461
462	ba = PE_boot_args();								/* Get the boot arguments */
463	lp = ba + 256;										/* Point to the end */
464
465	while(1) {											/* Step through, looking for our keywords */
466		phys = 0;										/* Assume virtual memory device */
467		ba = nonspace(ba, lp);							/* Find non-space */
468		if(ba >= lp) return;							/* We are done if no more... */
469		if(((ba[0] != 'v') && (ba[0] != 'p'))
470		  || (ba[1] != 'm') || (ba[2] != 'd') || (ba[4] != '=')
471		  || (ba[3] < '0') || (ba[3] > 'f')
472		  || ((ba[3] > '9') && (ba[3] < 'a'))) {		/* Is this of form "vmdx=" or "pmdx=" where x is hex digit? */
473
474			ba = getspace(ba, lp);						/* Find next white space or end */
475			continue;									/* Start looking for the next one */
476		}
477
478		if(ba[0] == 'p') phys = 1;						/* Set physical memory disk */
479
480		devid = ba[3] & 0xF;							/* Assume digit */
481		if(ba[3] > '9') devid += 9;						/* Adjust for hex digits */
482
483		ba = &ba[5];									/* Step past keyword */
484		ba = cvtnum(ba, lp, &base);						/* Convert base of memory disk */
485		if(ba >= lp) return;							/* Malformed one at the end, leave */
486		if(ba[0] != '.') continue;						/* If not length separater, try next... */
487		if(base & 0xFFF) continue;						/* Only allow page aligned stuff */
488
489		ba++;											/* Step past '.' */
490		ba = cvtnum(ba, lp, &size);						/* Try to convert it */
491		if(!size || (size & 0xFFF)) continue;			/* Allow only non-zer page size multiples */
492		if(ba < lp) {									/* If we are not at end, check end character */
493			if((ba[0] != ' ') && (ba[0] != 0)) continue;	/* End must be null or space */
494		}
495
496		dev = mdevadd(devid, base >> 12, (unsigned)size >> 12, phys);	/* Go add the device */
497	}
498
499#endif /* CONFIG_MEMDEV_INSECURE */
500
501	return;
502
503}
504
505#ifdef CONFIG_MEMDEV_INSECURE
506
507char *nonspace(char *pos, char *end) {					/* Find next non-space in string */
508
509	if(pos >= end) return end;							/* Don't go past end */
510	if(pos[0] == 0) return end;							/* If at null, make end */
511
512	while(1) {											/* Keep going */
513		if(pos[0] != ' ') return pos;					/* Leave if we found one */
514		pos++;											/* Stop */
515		if(pos >= end) return end;						/* Quit if we run off end */
516	}
517}
518
519char *getspace(char *pos, char *end) {					/* Find next non-space in string */
520
521	while(1) {											/* Keep going */
522		if(pos >= end) return end;						/* Don't go past end */
523		if(pos[0] == 0) return end;						/* Leave if we hit null */
524		if(pos[0] == ' ') return pos;					/* Leave if we found one */
525		pos++;											/* Stop */
526	}
527}
528
529char *cvtnum(char *pos, char *end, uint64_t *num) {		/* Convert to a number */
530
531	int rad, dig;
532
533	*num = 0;											/* Set answer to 0 to start */
534	rad = 10;
535
536	if(pos >= end) return end;							/* Don't go past end */
537	if(pos[0] == 0) return end;							/* If at null, make end */
538
539	if(pos[0] == '0' && ((pos[1] == 'x') || (pos[1] == 'x'))) {	/* A hex constant? */
540		rad = 16;
541		pos += 2;										/* Point to the number */
542	}
543
544	while(1) {											/* Convert it */
545
546		if(pos >= end) return end;						/* Don't go past end */
547		if(pos[0] == 0) return end;						/* If at null, make end */
548		if(pos[0] < '0') return pos;					/* Leave if non-digit */
549		dig = pos[0] & 0xF;								/* Extract digit */
550		if(pos[0] > '9') {								/* Is it bigger than 9? */
551			if(rad == 10) return pos;					/* Leave if not base 10 */
552			if(!(((pos[0] >= 'A') && (pos[0] <= 'F'))
553			  || ((pos[0] >= 'a') && (pos[0] <= 'f')))) return pos;	/* Leave if bogus char */
554			 dig = dig + 9;								/* Adjust for character */
555		}
556		*num = (*num * rad) + dig;						/* Accumulate the number */
557		pos++;											/* Step on */
558	}
559}
560
561#endif /* CONFIG_MEMDEV_INSECURE */
562
563dev_t mdevadd(int devid, uint64_t base, unsigned int size, int phys) {
564
565	int i;
566
567	if(devid < 0) {
568
569		devid = -1;
570		for(i = 0; i < 16; i++) {						/* Search all known memory devices */
571			if(!(mdev[i].mdFlags & mdInited)) {			/* Is this a free one? */
572				if(devid < 0)devid = i;					/* Remember first free one */
573				continue;								/* Skip check */
574			}
575			if(!(((base + size -1 ) < mdev[i].mdBase) || ((mdev[i].mdBase + mdev[i].mdSize - 1) < base))) {	/* Is there any overlap? */
576				panic("mdevadd: attempt to add overlapping memory device at %016llX-%016llX\n", mdev[i].mdBase, mdev[i].mdBase + mdev[i].mdSize - 1);
577			}
578		}
579		if(devid < 0) {									/* Do we have free slots? */
580			panic("mdevadd: attempt to add more than 16 memory devices\n");
581		}
582	}
583	else {
584		if(devid >= 16) {								/* Giving us something bogus? */
585			panic("mdevadd: attempt to explicitly add a bogus memory device: %08X\n", devid);
586		}
587		if(mdev[devid].mdFlags & mdInited) {			/* Already there? */
588			panic("mdevadd: attempt to explicitly add a previously defined memory device: %08X\n", devid);
589		}
590	}
591
592	if(mdevBMajor < 0) {								/* Have we gotten a major number yet? */
593		mdevBMajor = bdevsw_add(-1, &mdevbdevsw);		/* Add to the table and figure out a major number */
594		if (mdevBMajor < 0) {
595			printf("mdevadd: error - bdevsw_add() returned %d\n", mdevBMajor);
596			return -1;
597		}
598	}
599
600	if(mdevCMajor < 0) {								/* Have we gotten a major number yet? */
601		mdevCMajor = cdevsw_add_with_bdev(-1, &mdevcdevsw, mdevBMajor);		/* Add to the table and figure out a major number */
602		if (mdevCMajor < 0) {
603			printf("ramdevice_init: error - cdevsw_add() returned %d\n", mdevCMajor);
604			return -1;
605		}
606	}
607
608	mdev[devid].mdBDev = makedev(mdevBMajor, devid);	/* Get the device number */
609	mdev[devid].mdbdevb = devfs_make_node(mdev[devid].mdBDev, DEVFS_BLOCK,	/* Make the node */
610						  UID_ROOT, GID_OPERATOR,
611						  0600, "md%d", devid);
612	if (mdev[devid].mdbdevb == NULL) {					/* Did we make one? */
613		printf("mdevadd: devfs_make_node for block failed!\n");
614		return -1;										/* Nope... */
615	}
616
617	mdev[devid].mdCDev = makedev(mdevCMajor, devid);	/* Get the device number */
618	mdev[devid].mdcdevb = devfs_make_node(mdev[devid].mdCDev, DEVFS_CHAR,		/* Make the node */
619						  UID_ROOT, GID_OPERATOR,
620						  0600, "rmd%d", devid);
621	if (mdev[devid].mdcdevb == NULL) {					/* Did we make one? */
622		printf("mdevadd: devfs_make_node for character failed!\n");
623		return -1;										/* Nope... */
624	}
625
626	mdev[devid].mdBase = base;							/* Set the base address of ram disk */
627	mdev[devid].mdSize = size;							/* Set the length of the ram disk */
628	mdev[devid].mdSecsize = DEV_BSIZE;					/* Set starting block size */
629	if(phys) mdev[devid].mdFlags |= mdPhys;				/* Show that we are in physical memory */
630	mdev[devid].mdFlags |= mdInited;					/* Show we are all set up */
631	printf("Added memory device md%x/rmd%x (%08X/%08X) at %016llX for %016llX\n",
632		   devid, devid, mdev[devid].mdBDev, mdev[devid].mdCDev, base << 12, (uint64_t)size << 12);
633	return mdev[devid].mdBDev;
634}
635
636
637dev_t mdevlookup(int devid) {
638
639	if((devid < 0) || (devid > 15)) return -1;			/* Filter any bogus requests */
640	if(!(mdev[devid].mdFlags & mdInited)) return -1;	/* This one hasn't been defined */
641	return mdev[devid].mdBDev;							/* Return the device number */
642}
643
644void mdevremoveall(void) {
645
646	int i;
647
648	for(i = 0; i < 16; i++) {
649		if(!(mdev[i].mdFlags & mdInited)) continue;	/* Ignore unused mdevs */
650
651		devfs_remove(mdev[i].mdbdevb);			/* Remove the block device */
652		devfs_remove(mdev[i].mdcdevb);			/* Remove the character device */
653
654		mdev[i].mdBase = 0;				/* Clear the mdev's storage */
655		mdev[i].mdSize = 0;
656		mdev[i].mdSecsize = 0;
657		mdev[i].mdFlags = 0;
658		mdev[i].mdBDev = 0;
659		mdev[i].mdCDev = 0;
660		mdev[i].mdbdevb = 0;
661		mdev[i].mdcdevb = 0;
662	}
663}
664