2  * Copyright (c) 2004-2019 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   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. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  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. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  29  * Copyright (c) 1988 University of Utah. 
  30  * Copyright (c) 1990, 1993 
  31  *      The Regents of the University of California.  All rights reserved. 
  33  * This code is derived from software contributed to Berkeley by 
  34  * the Systems Programming Group of the University of Utah Computer 
  37  * Redistribution and use in source and binary forms, with or without 
  38  * modification, are permitted provided that the following conditions 
  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. 
  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 
  65  * from: Utah Hdr: vn.c 1.13 94/04/02 
  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 $ 
  74  * Block interface to a ramdisk. 
  78 #include <sys/param.h> 
  79 #include <sys/kernel.h> 
  80 #include <sys/mount.h> 
  81 #include <sys/namei.h> 
  84 #include <sys/malloc.h> 
  85 #include <sys/mount.h> 
  86 #include <sys/fcntl.h> 
  91 #include <sys/uio_internal.h> 
  92 #include <libkern/libkern.h> 
  95 #include <vm/vm_pager.h> 
  96 #include <mach/memory_object_types.h> 
  97 #include <kern/debug.h> 
  99 #include <miscfs/devfs/devfs.h> 
 102 void            mdevinit(int the_cnt
); 
 104 static open_close_fcn_t mdevopen
; 
 105 static open_close_fcn_t mdevclose
; 
 106 static psize_fcn_t              mdevsize
; 
 107 static strategy_fcn_t   mdevstrategy
; 
 108 static int                              mdevbioctl(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc 
*p
); 
 109 static int                              mdevcioctl(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc 
*p
); 
 110 static int                              mdevrw(dev_t dev
, struct uio 
*uio
, int ioflag
); 
 112 #ifdef CONFIG_MEMDEV_INSECURE 
 113 static char *                   nonspace(char *pos
, char *end
); 
 114 static char *                   getspace(char *pos
, char *end
); 
 115 static char *                   cvtnum(char *pos
, char *end
, uint64_t *num
); 
 116 #endif /* CONFIG_MEMDEV_INSECURE */ 
 118 extern void             bcopy_phys(addr64_t from
, addr64_t to
, vm_size_t bytes
); 
 119 extern void             mapping_set_mod(ppnum_t pn
); 
 120 extern ppnum_t  
pmap_find_phys(pmap_t pmap
, addr64_t va
); 
 123  * Maximal number of memory devices. 
 125 #define NB_MAX_MDEVICES (16) 
 129  *      D_DISK          we want to look like a disk 
 130  *      D_CANFREE       We support B_FREEBUF 
 133 static const struct bdevsw mdevbdevsw 
= { 
 135         .d_close    
= mdevclose
, 
 136         .d_strategy 
= mdevstrategy
, 
 137         .d_ioctl    
= mdevbioctl
, 
 143 static const struct cdevsw mdevcdevsw 
= { 
 145         .d_close      
= mdevclose
, 
 148         .d_ioctl      
= mdevcioctl
, 
 150         .d_reset      
= eno_reset
, 
 152         .d_select     
= eno_select
, 
 154         .d_strategy   
= eno_strat
, 
 155         .d_reserved_1 
= eno_getc
, 
 156         .d_reserved_2 
= eno_putc
, 
 161         uint64_t        mdBase
;         /* file size in bytes */ 
 162         uint32_t        mdSize
;         /* file size in bytes */ 
 163         int                     mdFlags
;        /* flags */ 
 164         int                     mdSecsize
;      /* sector size */ 
 165         int                     mdBDev
;         /* Block device number */ 
 166         int                     mdCDev
;         /* Character device number */ 
 169 } mdev
[NB_MAX_MDEVICES
]; 
 172 #define mdInited        0x01    /* This device defined */ 
 173 #define mdRO            0x02    /* This device is read-only */ 
 174 #define mdPhys          0x04    /* This device is in physical memory */ 
 179 static int      mdevioctl(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc 
*p
, int is_char
); 
 180 dev_t           
mdevadd(int devid
, uint64_t base
, unsigned int size
, int phys
); 
 181 dev_t           
mdevlookup(int devid
); 
 182 void            mdevremoveall(void); 
 183 int             mdevgetrange(int devid
, uint64_t *base
, uint64_t *size
); 
 186 mdevclose(__unused dev_t dev
, __unused 
int flags
, 
 187     __unused 
int devtype
, __unused 
struct proc 
*p
) 
 193 mdevopen(dev_t dev
, int flags
, __unused 
int devtype
, __unused 
struct proc 
*p
) 
 197         devid 
= minor(dev
);                                                                     /* Get minor device number */ 
 199         if (devid 
>= NB_MAX_MDEVICES
) { 
 200                 return ENXIO
;                                                                 /* Not valid */ 
 202         if ((flags 
& FWRITE
) && (mdev
[devid
].mdFlags 
& mdRO
)) { 
 203                 return EACCES
;                                                /* Currently mounted RO */ 
 209 mdevrw(dev_t dev
, struct uio 
*uio
, __unused 
int ioflag
) 
 214         enum uio_seg    saveflag
; 
 216         devid 
= minor(dev
);                                                                     /* Get minor device number */ 
 218         if (devid 
>= NB_MAX_MDEVICES
) { 
 219                 return ENXIO
;                                                                 /* Not valid */ 
 221         if (!(mdev
[devid
].mdFlags 
& mdInited
)) { 
 222                 return ENXIO
;                                 /* Have we actually been defined yet? */ 
 224         mdata 
= ((addr64_t
)mdev
[devid
].mdBase 
<< 12) + uio
->uio_offset
; /* Point to the area in "file" */ 
 226         saveflag 
= uio
->uio_segflg
;                                                     /* Remember what the request is */ 
 228         if (UIO_IS_USER_SPACE(uio
) == 0 && UIO_IS_SYS_SPACE(uio
) == 0) { 
 229                 panic("mdevrw - invalid uio_segflg\n"); 
 231 #endif /* LP64_DEBUG */ 
 232         /* Make sure we are moving from physical ram if physical device */ 
 233         if (mdev
[devid
].mdFlags 
& mdPhys
) { 
 234                 if (uio
->uio_segflg 
== UIO_USERSPACE64
) { 
 235                         uio
->uio_segflg 
= UIO_PHYS_USERSPACE64
; 
 236                 } else if (uio
->uio_segflg 
== UIO_USERSPACE32
) { 
 237                         uio
->uio_segflg 
= UIO_PHYS_USERSPACE32
; 
 239                         uio
->uio_segflg 
= UIO_PHYS_USERSPACE
; 
 242         status 
= uiomove64(mdata
, (int)uio_resid(uio
), uio
);    /* Move the data */ 
 243         uio
->uio_segflg 
= saveflag
;                                                     /* Restore the flag */ 
 249 mdevstrategy(struct buf 
*bp
) 
 251         unsigned int left
, lop
, csize
; 
 252         vm_offset_t vaddr
, blkoff
; 
 254         addr64_t paddr
, fvaddr
; 
 257         devid 
= minor(buf_device(bp
));                                                  /* Get minor device number */ 
 259         if ((mdev
[devid
].mdFlags 
& mdInited
) == 0) {            /* Have we actually been defined yet? */ 
 260                 buf_seterror(bp
, ENXIO
); 
 265         buf_setresid(bp
, buf_count(bp
));                                                /* Set byte count */ 
 267         blkoff 
= buf_blkno(bp
) * mdev
[devid
].mdSecsize
;         /* Get offset into file */ 
 270  *      Note that reading past end is an error, but reading at end is an EOF.  For these 
 271  *      we just return with resid == count. 
 274         if (blkoff 
>= (mdev
[devid
].mdSize 
<< 12)) {                     /* Are they trying to read/write at/after end? */ 
 275                 if (blkoff 
!= (mdev
[devid
].mdSize 
<< 12)) {              /* Are we trying to read after EOF? */ 
 276                         buf_seterror(bp
, EINVAL
);                                               /* Yeah, this is an error */ 
 278                 buf_biodone(bp
);                                                                /* Return */ 
 282         if ((blkoff 
+ buf_count(bp
)) > (mdev
[devid
].mdSize 
<< 12)) {            /* Will this read go past end? */ 
 283                 buf_setcount(bp
, (uint32_t)((mdev
[devid
].mdSize 
<< 12) - blkoff
));  /* Yes, trim to max */ 
 286          * make sure the buffer's data area is 
 289         if (buf_map(bp
, (caddr_t 
*)&vaddr
)) { 
 290                 panic("ramstrategy: buf_map failed\n"); 
 293         fvaddr 
= (mdev
[devid
].mdBase 
<< 12) + blkoff
;           /* Point to offset into ram disk */ 
 295         if (buf_flags(bp
) & B_READ
) {                                   /* Is this a read? */ 
 296                 if (!(mdev
[devid
].mdFlags 
& mdPhys
)) {                   /* Physical mapped disk? */ 
 297                         bcopy((void *)((uintptr_t)fvaddr
), 
 298                             (void *)vaddr
, (size_t)buf_count(bp
));      /* This is virtual, just get the data */ 
 300                         left 
= buf_count(bp
);                                           /* Init the amount left to copy */ 
 301                         while (left
) {                                                           /* Go until it is all copied */ 
 302                                 lop 
= min((4096 - (vaddr 
& 4095)), (4096 - (fvaddr 
& 4095)));   /* Get smallest amount left on sink and source */ 
 303                                 csize 
= min(lop
, left
);                                 /* Don't move more than we need to */ 
 305                                 pp 
= pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)vaddr
)); /* Get the sink physical address */ 
 306                                 if (!pp
) {                                                               /* Not found, what gives? */ 
 307                                         panic("mdevstrategy: sink address %016llX not mapped\n", (addr64_t
)((uintptr_t)vaddr
)); 
 309                                 paddr 
= (addr64_t
)(((addr64_t
)pp 
<< 12) | (addr64_t
)(vaddr 
& 4095));    /* Get actual address */ 
 310                                 bcopy_phys(fvaddr
, paddr
, csize
);               /* Copy this on in */ 
 311                                 mapping_set_mod((ppnum_t
)(paddr 
>> 12));        /* Make sure we know that it is modified */ 
 313                                 left 
= left 
- csize
;                                    /* Calculate what is left */ 
 314                                 vaddr 
= vaddr 
+ csize
;                                  /* Move to next sink address */ 
 315                                 fvaddr 
= fvaddr 
+ csize
;                                /* Bump to next physical address */ 
 318         } else {                                                                                        /* This is a write */ 
 319                 if (!(mdev
[devid
].mdFlags 
& mdPhys
)) {                   /* Physical mapped disk? */ 
 320                         bcopy((void *)vaddr
, (void *)((uintptr_t)fvaddr
), 
 321                             (size_t)buf_count(bp
));             /* This is virtual, just put the data */ 
 323                         left 
= buf_count(bp
);                                           /* Init the amount left to copy */ 
 324                         while (left
) {                                                           /* Go until it is all copied */ 
 325                                 lop 
= min((4096 - (vaddr 
& 4095)), (4096 - (fvaddr 
& 4095)));   /* Get smallest amount left on sink and source */ 
 326                                 csize 
= min(lop
, left
);                                 /* Don't move more than we need to */ 
 328                                 pp 
= pmap_find_phys(kernel_pmap
, (addr64_t
)((uintptr_t)vaddr
)); /* Get the source physical address */ 
 329                                 if (!pp
) {                                                               /* Not found, what gives? */ 
 330                                         panic("mdevstrategy: source address %016llX not mapped\n", (addr64_t
)((uintptr_t)vaddr
)); 
 332                                 paddr 
= (addr64_t
)(((addr64_t
)pp 
<< 12) | (addr64_t
)(vaddr 
& 4095));    /* Get actual address */ 
 334                                 bcopy_phys(paddr
, fvaddr
, csize
);               /* Move this on out */ 
 336                                 left 
= left 
- csize
;                                    /* Calculate what is left */ 
 337                                 vaddr 
= vaddr 
+ csize
;                                  /* Move to next sink address */ 
 338                                 fvaddr 
= fvaddr 
+ csize
;                                /* Bump to next physical address */ 
 343          * buf_unmap takes care of all the cases 
 344          * it will unmap the buffer from kernel 
 345          * virtual space if that was the state 
 350         buf_setresid(bp
, 0);                                                                    /* Nothing more to do */ 
 351         buf_biodone(bp
);                                                                        /* Say we've finished */ 
 355 mdevbioctl(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc 
*p
) 
 357         return mdevioctl(dev
, cmd
, data
, flag
, p
, 0); 
 361 mdevcioctl(dev_t dev
, u_long cmd
, caddr_t data
, int flag
, struct proc 
*p
) 
 363         return mdevioctl(dev
, cmd
, data
, flag
, p
, 1); 
 367 mdevioctl(dev_t dev
, u_long cmd
, caddr_t data
, __unused 
int flag
, 
 368     struct proc 
*p
, int is_char
) 
 374         dk_memdev_info_t 
* memdev_info
; 
 376         devid 
= minor(dev
);                                                                     /* Get minor device number */ 
 378         if (devid 
>= NB_MAX_MDEVICES
) { 
 379                 return ENXIO
;                                                                 /* Not valid */ 
 381         error 
= proc_suser(p
);                  /* Are we superman? */ 
 383                 return error
;                                                         /* Nope... */ 
 385         f 
= (u_int32_t
*)data
; 
 386         o 
= (u_int64_t 
*)data
; 
 387         memdev_info 
= (dk_memdev_info_t 
*) data
; 
 390         case DKIOCGETMAXBLOCKCOUNTREAD
: 
 394         case DKIOCGETMAXBLOCKCOUNTWRITE
: 
 398         case DKIOCGETMAXSEGMENTCOUNTREAD
: 
 402         case DKIOCGETMAXSEGMENTCOUNTWRITE
: 
 406         case DKIOCGETBLOCKSIZE
: 
 407                 *f 
= mdev
[devid
].mdSecsize
; 
 410         case DKIOCSETBLOCKSIZE
: 
 412                         return ENODEV
;                                        /* We can only do this for a block */ 
 414                 if (*f 
< DEV_BSIZE
) { 
 415                         return EINVAL
;                                /* Too short? */ 
 417                 mdev
[devid
].mdSecsize 
= *f
;                                             /* set the new block size */ 
 420         case DKIOCISWRITABLE
: 
 424         case DKIOCGETBLOCKCOUNT
: 
 425                 if (!(mdev
[devid
].mdFlags 
& mdInited
)) { 
 428                 *o 
= ((mdev
[devid
].mdSize 
<< 12) + mdev
[devid
].mdSecsize 
- 1) / mdev
[devid
].mdSecsize
; 
 432          * We're interested in the following bits of information: 
 433          *   Are you a memory-backed device (always yes, in this case)? 
 434          *   Physical memory (mdPhys)? 
 435          *   What is your base page? 
 438         case DKIOCGETMEMDEVINFO
: 
 439                 if (!(mdev
[devid
].mdFlags 
& mdInited
)) { 
 442                 memdev_info
->mi_mdev 
= TRUE
; 
 443                 memdev_info
->mi_phys 
= (mdev
[devid
].mdFlags 
& mdPhys
) ? TRUE 
: FALSE
; 
 444                 memdev_info
->mi_base 
= (uint32_t)mdev
[devid
].mdBase
; 
 445                 memdev_info
->mi_size 
= mdev
[devid
].mdSize
; 
 461         devid 
= minor(dev
);                                                                     /* Get minor device number */ 
 462         if (devid 
>= NB_MAX_MDEVICES
) { 
 463                 return ENXIO
;                                                                 /* Not valid */ 
 465         if ((mdev
[devid
].mdFlags 
& mdInited
) == 0) { 
 466                 return -1;                                            /* Not inited yet */ 
 468         return mdev
[devid
].mdSecsize
; 
 471 #include <pexpert/pexpert.h> 
 474 mdevinit(__unused 
int the_cnt
) 
 476 #ifdef CONFIG_MEMDEV_INSECURE 
 485         ba 
= PE_boot_args();                                                            /* Get the boot arguments */ 
 486         lp 
= ba 
+ 256;                                                                          /* Point to the end */ 
 488         while (1) {                                                                                      /* Step through, looking for our keywords */ 
 489                 phys 
= 0;                                                                               /* Assume virtual memory device */ 
 490                 ba 
= nonspace(ba
, lp
);                                                  /* Find non-space */ 
 492                         return;                                                         /* We are done if no more... */ 
 494                 if (((ba
[0] != 'v') && (ba
[0] != 'p')) 
 495                     || (ba
[1] != 'm') || (ba
[2] != 'd') || (ba
[4] != '=') 
 496                     || (ba
[3] < '0') || (ba
[3] > 'f') 
 497                     || ((ba
[3] > '9') && (ba
[3] < 'a'))) {              /* Is this of form "vmdx=" or "pmdx=" where x is hex digit? */ 
 498                         ba 
= getspace(ba
, lp
);                                          /* Find next white space or end */ 
 499                         continue;                                                                       /* Start looking for the next one */ 
 503                         phys 
= 1;                                                       /* Set physical memory disk */ 
 505                 devid 
= ba
[3] & 0xF;                                                    /* Assume digit */ 
 507                         devid 
+= 9;                                                     /* Adjust for hex digits */ 
 509                 ba 
= &ba
[5];                                                                    /* Step past keyword */ 
 510                 ba 
= cvtnum(ba
, lp
, &base
);                                             /* Convert base of memory disk */ 
 512                         return;                                                         /* Malformed one at the end, leave */ 
 515                         continue;                                                       /* If not length separater, try next... */ 
 518                         continue;                                                       /* Only allow page aligned stuff */ 
 520                 ba
++;                                                                                   /* Step past '.' */ 
 521                 ba 
= cvtnum(ba
, lp
, &size
);                                             /* Try to convert it */ 
 522                 if (!size 
|| (size 
& 0xFFF)) { 
 523                         continue;                                       /* Allow only non-zer page size multiples */ 
 525                 if (ba 
< lp
) {                                                                   /* If we are not at end, check end character */ 
 526                         if ((ba
[0] != ' ') && (ba
[0] != 0)) { 
 527                                 continue;                               /* End must be null or space */ 
 531                 dev 
= mdevadd(devid
, base 
>> 12, (unsigned)size 
>> 12, phys
);   /* Go add the device */ 
 534 #endif /* CONFIG_MEMDEV_INSECURE */ 
 539 #ifdef CONFIG_MEMDEV_INSECURE 
 542 nonspace(char *pos
, char *end
)                                          /* Find next non-space in string */ 
 545                 return end
;                                                             /* Don't go past end */ 
 548                 return end
;                                                             /* If at null, make end */ 
 550         while (1) {                                                                                      /* Keep going */ 
 552                         return pos
;                                             /* Leave if we found one */ 
 556                         return end
;                                                     /* Quit if we run off end */ 
 562 getspace(char *pos
, char *end
)                                          /* Find next non-space in string */ 
 564         while (1) {                                                                                      /* Keep going */ 
 566                         return end
;                                                     /* Don't go past end */ 
 569                         return end
;                                                     /* Leave if we hit null */ 
 572                         return pos
;                                             /* Leave if we found one */ 
 579 cvtnum(char *pos
, char *end
, uint64_t *num
)                     /* Convert to a number */ 
 583         *num 
= 0;                                                                                       /* Set answer to 0 to start */ 
 587                 return end
;                                                             /* Don't go past end */ 
 590                 return end
;                                                             /* If at null, make end */ 
 592         if (pos
[0] == '0' && ((pos
[1] == 'x') || (pos
[1] == 'x'))) {     /* A hex constant? */ 
 594                 pos 
+= 2;                                                                               /* Point to the number */ 
 597         while (1) {                                                                                      /* Convert it */ 
 599                         return end
;                                                     /* Don't go past end */ 
 602                         return end
;                                                     /* If at null, make end */ 
 605                         return pos
;                                             /* Leave if non-digit */ 
 607                 dig 
= pos
[0] & 0xF;                                                             /* Extract digit */ 
 608                 if (pos
[0] > '9') {                                                              /* Is it bigger than 9? */ 
 610                                 return pos
;                                             /* Leave if not base 10 */ 
 612                         if (!(((pos
[0] >= 'A') && (pos
[0] <= 'F')) 
 613                             || ((pos
[0] >= 'a') && (pos
[0] <= 'f')))) { 
 614                                 return pos
;                                     /* Leave if bogus char */ 
 616                         dig 
= dig 
+ 9;                                                          /* Adjust for character */ 
 618                 *num 
= (*num 
* rad
) + dig
;                                              /* Accumulate the number */ 
 623 #endif /* CONFIG_MEMDEV_INSECURE */ 
 626 mdevadd(int devid
, uint64_t base
, unsigned int size
, int phys
) 
 632                 for (i 
= 0; i 
< NB_MAX_MDEVICES
; i
++) {                                          /* Search all known memory devices */ 
 633                         if (!(mdev
[i
].mdFlags 
& mdInited
)) {                     /* Is this a free one? */ 
 635                                         devid 
= i
;                                      /* Remember first free one */ 
 637                                 continue;                                                               /* Skip check */ 
 639                         if (!(((base 
+ size 
- 1) < mdev
[i
].mdBase
) || ((mdev
[i
].mdBase 
+ mdev
[i
].mdSize 
- 1) < base
))) { /* Is there any overlap? */ 
 640                                 panic("mdevadd: attempt to add overlapping memory device at %016llX-%016llX\n", mdev
[i
].mdBase
, mdev
[i
].mdBase 
+ mdev
[i
].mdSize 
- 1); 
 643                 if (devid 
< 0) {                                                                 /* Do we have free slots? */ 
 644                         panic("mdevadd: attempt to add more than %d memory devices\n", NB_MAX_MDEVICES
); 
 647                 if (devid 
>= NB_MAX_MDEVICES
) {                                                          /* Giving us something bogus? */ 
 648                         panic("mdevadd: attempt to explicitly add a bogus memory device: %08X\n", devid
); 
 650                 if (mdev
[devid
].mdFlags 
& mdInited
) {                    /* Already there? */ 
 651                         panic("mdevadd: attempt to explicitly add a previously defined memory device: %08X\n", devid
); 
 655         if (mdevBMajor 
< 0) {                                                            /* Have we gotten a major number yet? */ 
 656                 mdevBMajor 
= bdevsw_add(-1, &mdevbdevsw
);               /* Add to the table and figure out a major number */ 
 657                 if (mdevBMajor 
< 0) { 
 658                         printf("mdevadd: error - bdevsw_add() returned %d\n", mdevBMajor
); 
 663         if (mdevCMajor 
< 0) {                                                            /* Have we gotten a major number yet? */ 
 664                 mdevCMajor 
= cdevsw_add_with_bdev(-1, &mdevcdevsw
, mdevBMajor
);         /* Add to the table and figure out a major number */ 
 665                 if (mdevCMajor 
< 0) { 
 666                         printf("ramdevice_init: error - cdevsw_add() returned %d\n", mdevCMajor
); 
 671         mdev
[devid
].mdBDev 
= makedev(mdevBMajor
, devid
);        /* Get the device number */ 
 672         mdev
[devid
].mdbdevb 
= devfs_make_node(mdev
[devid
].mdBDev
, DEVFS_BLOCK
,  /* Make the node */ 
 673             UID_ROOT
, GID_OPERATOR
, 
 674             0600, "md%d", devid
); 
 675         if (mdev
[devid
].mdbdevb 
== NULL
) {                                      /* Did we make one? */ 
 676                 printf("mdevadd: devfs_make_node for block failed!\n"); 
 677                 return -1;                                                                              /* Nope... */ 
 680         mdev
[devid
].mdCDev 
= makedev(mdevCMajor
, devid
);        /* Get the device number */ 
 681         mdev
[devid
].mdcdevb 
= devfs_make_node(mdev
[devid
].mdCDev
, DEVFS_CHAR
,           /* Make the node */ 
 682             UID_ROOT
, GID_OPERATOR
, 
 683             0600, "rmd%d", devid
); 
 684         if (mdev
[devid
].mdcdevb 
== NULL
) {                                      /* Did we make one? */ 
 685                 printf("mdevadd: devfs_make_node for character failed!\n"); 
 686                 return -1;                                                                              /* Nope... */ 
 689         mdev
[devid
].mdBase 
= base
;                                                      /* Set the base address of ram disk */ 
 690         mdev
[devid
].mdSize 
= size
;                                                      /* Set the length of the ram disk */ 
 691         mdev
[devid
].mdSecsize 
= DEV_BSIZE
;                                      /* Set starting block size */ 
 693                 mdev
[devid
].mdFlags 
|= mdPhys
;                          /* Show that we are in physical memory */ 
 695         mdev
[devid
].mdFlags 
|= mdInited
;                                        /* Show we are all set up */ 
 696         printf("Added memory device md%x/rmd%x (%08X/%08X) at %016llX for %016llX\n", 
 697             devid
, devid
, mdev
[devid
].mdBDev
, mdev
[devid
].mdCDev
, base 
<< 12, (uint64_t)size 
<< 12); 
 698         return mdev
[devid
].mdBDev
; 
 703 mdevlookup(int devid
) 
 705         if ((devid 
< 0) || (devid 
>= NB_MAX_MDEVICES
)) { 
 706                 return -1;                                                              /* Filter any bogus requests */ 
 708         if (!(mdev
[devid
].mdFlags 
& mdInited
)) { 
 709                 return -1;                                      /* This one hasn't been defined */ 
 711         return mdev
[devid
].mdBDev
;                                                      /* Return the device number */ 
 719         for (i 
= 0; i 
< NB_MAX_MDEVICES
; i
++) { 
 720                 if (!(mdev
[i
].mdFlags 
& mdInited
)) { 
 721                         continue;                               /* Ignore unused mdevs */ 
 723                 devfs_remove(mdev
[i
].mdbdevb
);                  /* Remove the block device */ 
 724                 devfs_remove(mdev
[i
].mdcdevb
);                  /* Remove the character device */ 
 726                 mdev
[i
].mdBase 
= 0;                             /* Clear the mdev's storage */ 
 728                 mdev
[i
].mdSecsize 
= 0; 
 738 mdevgetrange(int devid
, uint64_t *base
, uint64_t *size
) 
 743         /* filter invalid request */ 
 744         if ((devid 
< 0) || (devid 
>= NB_MAX_MDEVICES
)) { 
 748         /* filter non-initialized memory devices */ 
 749         if ((mdev
[devid
].mdFlags 
& mdInited
) == 0) { 
 753         *base 
= mdev
[devid
].mdBase 
<< 12; 
 754         *size 
= mdev
[devid
].mdSize 
<< 12; 
 756         /* make sure (base, size) is a valid range and will not overflow */ 
 757         assert(*size 
< (UINT64_MAX 
- *base
));