The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/drivers/memory/memory.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* This file contains the device dependent part of the drivers for the
    2  * following special files:
    3  *     /dev/ram         - RAM disk 
    4  *     /dev/mem         - absolute memory
    5  *     /dev/kmem        - kernel virtual memory
    6  *     /dev/null        - null device (data sink)
    7  *     /dev/boot        - boot device loaded from boot image 
    8  *     /dev/zero        - null byte stream generator
    9  *
   10  *  Changes:
   11  *      Apr 29, 2005    added null byte generator  (Jorrit N. Herder)
   12  *      Apr 09, 2005    added support for boot device  (Jorrit N. Herder)
   13  *      Jul 26, 2004    moved RAM driver to user-space  (Jorrit N. Herder)
   14  *      Apr 20, 1992    device dependent/independent split  (Kees J. Bot)
   15  */
   16 
   17 #include "../drivers.h"
   18 #include "../libdriver/driver.h"
   19 #include <sys/ioc_memory.h>
   20 #include "../../kernel/const.h"
   21 #include "../../kernel/config.h"
   22 #include "../../kernel/type.h"
   23 
   24 #include "assert.h"
   25 
   26 #define NR_DEVS            6            /* number of minor devices */
   27 
   28 PRIVATE struct device m_geom[NR_DEVS];  /* base and size of each device */
   29 PRIVATE int m_seg[NR_DEVS];             /* segment index of each device */
   30 PRIVATE int m_device;                   /* current device */
   31 PRIVATE struct kinfo kinfo;             /* kernel information */ 
   32 PRIVATE struct machine machine;         /* machine information */ 
   33 
   34 extern int errno;                       /* error number for PM calls */
   35 
   36 FORWARD _PROTOTYPE( char *m_name, (void)                                );
   37 FORWARD _PROTOTYPE( struct device *m_prepare, (int device)              );
   38 FORWARD _PROTOTYPE( int m_transfer, (int proc_nr, int opcode, off_t position,
   39                                         iovec_t *iov, unsigned nr_req)  );
   40 FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr)  );
   41 FORWARD _PROTOTYPE( void m_init, (void) );
   42 FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr)    );
   43 FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry)          );
   44 
   45 /* Entry points to this driver. */
   46 PRIVATE struct driver m_dtab = {
   47   m_name,       /* current device's name */
   48   m_do_open,    /* open or mount */
   49   do_nop,       /* nothing on a close */
   50   m_ioctl,      /* specify ram disk geometry */
   51   m_prepare,    /* prepare for I/O on a given minor device */
   52   m_transfer,   /* do the I/O */
   53   nop_cleanup,  /* no need to clean up */
   54   m_geometry,   /* memory device "geometry" */
   55   nop_signal,   /* system signals */
   56   nop_alarm,
   57   nop_cancel,
   58   nop_select,
   59   NULL,
   60   NULL
   61 };
   62 
   63 /* Buffer for the /dev/zero null byte feed. */
   64 #define ZERO_BUF_SIZE                   1024
   65 PRIVATE char dev_zero[ZERO_BUF_SIZE];
   66 
   67 #define click_to_round_k(n) \
   68         ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
   69 
   70 /*===========================================================================*
   71  *                                 main                                      *
   72  *===========================================================================*/
   73 PUBLIC int main(void)
   74 {
   75 /* Main program. Initialize the memory driver and start the main loop. */
   76   m_init();                     
   77   driver_task(&m_dtab);         
   78   return(OK);                           
   79 }
   80 
   81 /*===========================================================================*
   82  *                               m_name                                      *
   83  *===========================================================================*/
   84 PRIVATE char *m_name()
   85 {
   86 /* Return a name for the current device. */
   87   static char name[] = "memory";
   88   return name;  
   89 }
   90 
   91 /*===========================================================================*
   92  *                              m_prepare                                    *
   93  *===========================================================================*/
   94 PRIVATE struct device *m_prepare(device)
   95 int device;
   96 {
   97 /* Prepare for I/O on a device: check if the minor device number is ok. */
   98   if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
   99   m_device = device;
  100 
  101   return(&m_geom[device]);
  102 }
  103 
  104 /*===========================================================================*
  105  *                              m_transfer                                   *
  106  *===========================================================================*/
  107 PRIVATE int m_transfer(proc_nr, opcode, position, iov, nr_req)
  108 int proc_nr;                    /* process doing the request */
  109 int opcode;                     /* DEV_GATHER or DEV_SCATTER */
  110 off_t position;                 /* offset on device to read or write */
  111 iovec_t *iov;                   /* pointer to read or write request vector */
  112 unsigned nr_req;                /* length of request vector */
  113 {
  114 /* Read or write one the driver's minor devices. */
  115   phys_bytes mem_phys;
  116   int seg;
  117   unsigned count, left, chunk;
  118   vir_bytes user_vir;
  119   struct device *dv;
  120   unsigned long dv_size;
  121   int s;
  122 
  123   /* Get minor device number and check for /dev/null. */
  124   dv = &m_geom[m_device];
  125   dv_size = cv64ul(dv->dv_size);
  126 
  127   while (nr_req > 0) {
  128 
  129         /* How much to transfer and where to / from. */
  130         count = iov->iov_size;
  131         user_vir = iov->iov_addr;
  132 
  133         switch (m_device) {
  134 
  135         /* No copying; ignore request. */
  136         case NULL_DEV:
  137             if (opcode == DEV_GATHER) return(OK);       /* always at EOF */
  138             break;
  139 
  140         /* Virtual copying. For RAM disk, kernel memory and boot device. */
  141         case RAM_DEV:
  142         case KMEM_DEV:
  143         case BOOT_DEV:
  144             if (position >= dv_size) return(OK);        /* check for EOF */
  145             if (position + count > dv_size) count = dv_size - position;
  146             seg = m_seg[m_device];
  147 
  148             if (opcode == DEV_GATHER) {                 /* copy actual data */
  149                 sys_vircopy(SELF,seg,position, proc_nr,D,user_vir, count);
  150             } else {
  151                 sys_vircopy(proc_nr,D,user_vir, SELF,seg,position, count);
  152             }
  153             break;
  154 
  155         /* Physical copying. Only used to access entire memory. */
  156         case MEM_DEV:
  157             if (position >= dv_size) return(OK);        /* check for EOF */
  158             if (position + count > dv_size) count = dv_size - position;
  159             mem_phys = cv64ul(dv->dv_base) + position;
  160 
  161             if (opcode == DEV_GATHER) {                 /* copy data */
  162                 sys_physcopy(NONE, PHYS_SEG, mem_phys, 
  163                         proc_nr, D, user_vir, count);
  164             } else {
  165                 sys_physcopy(proc_nr, D, user_vir, 
  166                         NONE, PHYS_SEG, mem_phys, count);
  167             }
  168             break;
  169 
  170         /* Null byte stream generator. */
  171         case ZERO_DEV:
  172             if (opcode == DEV_GATHER) {
  173                 left = count;
  174                 while (left > 0) {
  175                     chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left;
  176                     if (OK != (s=sys_vircopy(SELF, D, (vir_bytes) dev_zero, 
  177                             proc_nr, D, user_vir, chunk)))
  178                         report("MEM","sys_vircopy failed", s);
  179                     left -= chunk;
  180                     user_vir += chunk;
  181                 }
  182             }
  183             break;
  184 
  185         /* Unknown (illegal) minor device. */
  186         default:
  187             return(EINVAL);
  188         }
  189 
  190         /* Book the number of bytes transferred. */
  191         position += count;
  192         iov->iov_addr += count;
  193         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
  194 
  195   }
  196   return(OK);
  197 }
  198 
  199 /*===========================================================================*
  200  *                              m_do_open                                    *
  201  *===========================================================================*/
  202 PRIVATE int m_do_open(dp, m_ptr)
  203 struct driver *dp;
  204 message *m_ptr;
  205 {
  206 /* Check device number on open. */
  207   if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
  208   return(OK);
  209 }
  210 
  211 /*===========================================================================*
  212  *                              m_init                                       *
  213  *===========================================================================*/
  214 PRIVATE void m_init()
  215 {
  216   /* Initialize this task. All minor devices are initialized one by one. */
  217   phys_bytes ramdev_size;
  218   phys_bytes ramdev_base;
  219   message m;
  220   int i, s;
  221 
  222   if (OK != (s=sys_getkinfo(&kinfo))) {
  223       panic("MEM","Couldn't get kernel information.",s);
  224   }
  225 
  226   /* Install remote segment for /dev/kmem memory. */
  227   m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
  228   m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
  229   if (OK != (s=sys_segctl(&m_seg[KMEM_DEV], (u16_t *) &s, (vir_bytes *) &s, 
  230                 kinfo.kmem_base, kinfo.kmem_size))) {
  231       panic("MEM","Couldn't install remote segment.",s);
  232   }
  233 
  234   /* Install remote segment for /dev/boot memory, if enabled. */
  235   m_geom[BOOT_DEV].dv_base = cvul64(kinfo.bootdev_base);
  236   m_geom[BOOT_DEV].dv_size = cvul64(kinfo.bootdev_size);
  237   if (kinfo.bootdev_base > 0) {
  238       if (OK != (s=sys_segctl(&m_seg[BOOT_DEV], (u16_t *) &s, (vir_bytes *) &s, 
  239               kinfo.bootdev_base, kinfo.bootdev_size))) {
  240           panic("MEM","Couldn't install remote segment.",s);
  241       }
  242   }
  243 
  244   /* See if there are already RAM disk details at the Data Store server. */
  245   m.DS_KEY = MEMORY_MAJOR;
  246   if (OK == (s = _taskcall(DS_PROC_NR, DS_RETRIEVE, &m))) {
  247         ramdev_size = m.DS_VAL_L1;
  248         ramdev_base = m.DS_VAL_L2;
  249         printf("MEM retrieved size %u and base %u from DS, status %d\n",
  250                 ramdev_size, ramdev_base, s);
  251         if (OK != (s=sys_segctl(&m_seg[RAM_DEV], (u16_t *) &s, 
  252                 (vir_bytes *) &s, ramdev_base, ramdev_size))) {
  253                 panic("MEM","Couldn't install remote segment.",s);
  254         }
  255         m_geom[RAM_DEV].dv_base = cvul64(ramdev_base);
  256         m_geom[RAM_DEV].dv_size = cvul64(ramdev_size);
  257         printf("MEM stored retrieved details as new RAM disk\n");
  258   }
  259 
  260   /* Initialize /dev/zero. Simply write zeros into the buffer. */
  261   for (i=0; i<ZERO_BUF_SIZE; i++) {
  262        dev_zero[i] = '\0';
  263   }
  264 
  265   /* Set up memory ranges for /dev/mem. */
  266 #if (CHIP == INTEL)
  267   if (OK != (s=sys_getmachine(&machine))) {
  268       panic("MEM","Couldn't get machine information.",s);
  269   }
  270   if (! machine.protected) {
  271         m_geom[MEM_DEV].dv_size =   cvul64(0x100000); /* 1M for 8086 systems */
  272   } else {
  273 #if _WORD_SIZE == 2
  274         m_geom[MEM_DEV].dv_size =  cvul64(0x1000000); /* 16M for 286 systems */
  275 #else
  276         m_geom[MEM_DEV].dv_size = cvul64(0xFFFFFFFF); /* 4G-1 for 386 systems */
  277 #endif
  278   }
  279 #else /* !(CHIP == INTEL) */
  280 #if (CHIP == M68000)
  281   m_geom[MEM_DEV].dv_size = cvul64(MEM_BYTES);
  282 #else /* !(CHIP == M68000) */
  283 #error /* memory limit not set up */
  284 #endif /* !(CHIP == M68000) */
  285 #endif /* !(CHIP == INTEL) */
  286 }
  287 
  288 /*===========================================================================*
  289  *                              m_ioctl                                      *
  290  *===========================================================================*/
  291 PRIVATE int m_ioctl(dp, m_ptr)
  292 struct driver *dp;                      /* pointer to driver structure */
  293 message *m_ptr;                         /* pointer to control message */
  294 {
  295 /* I/O controls for the memory driver. Currently there is one I/O control:
  296  * - MIOCRAMSIZE: to set the size of the RAM disk.
  297  */
  298   struct device *dv;
  299 
  300   switch (m_ptr->REQUEST) {
  301     case MIOCRAMSIZE: {
  302         /* FS wants to create a new RAM disk with the given size. */
  303         phys_bytes ramdev_size;
  304         phys_bytes ramdev_base;
  305         message m;
  306         int s;
  307 
  308         /* Only FS can create RAM disk, and only on RAM disk device. */
  309         if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
  310         if (m_ptr->DEVICE != RAM_DEV) return(EINVAL);
  311         if ((dv = m_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
  312 
  313         /* Try to allocate a piece of memory for the RAM disk. */
  314         ramdev_size = m_ptr->POSITION;
  315         if (allocmem(ramdev_size, &ramdev_base) < 0) {
  316             report("MEM", "warning, allocmem failed", errno);
  317             return(ENOMEM);
  318         }
  319 
  320         /* Store the values we got in the data store so we can retrieve
  321          * them later on, in the unfortunate event of a crash.
  322          */
  323         m.DS_KEY = MEMORY_MAJOR;
  324         m.DS_VAL_L1 = ramdev_size;
  325         m.DS_VAL_L2 = ramdev_base;
  326         if (OK != (s = _taskcall(DS_PROC_NR, DS_PUBLISH, &m))) {
  327                 panic("MEM","Couldn't store RAM disk details at DS.",s);
  328         }
  329         printf("MEM stored size %u and base %u at DS, status %d\n",
  330             ramdev_size, ramdev_base, s);
  331 
  332         if (OK != (s=sys_segctl(&m_seg[RAM_DEV], (u16_t *) &s, 
  333                 (vir_bytes *) &s, ramdev_base, ramdev_size))) {
  334                 panic("MEM","Couldn't install remote segment.",s);
  335         }
  336 
  337         dv->dv_base = cvul64(ramdev_base);
  338         dv->dv_size = cvul64(ramdev_size);
  339         break;
  340     }
  341 
  342     default:
  343         return(do_diocntl(&m_dtab, m_ptr));
  344   }
  345   return(OK);
  346 }
  347 
  348 /*===========================================================================*
  349  *                              m_geometry                                   *
  350  *===========================================================================*/
  351 PRIVATE void m_geometry(entry)
  352 struct partition *entry;
  353 {
  354   /* Memory devices don't have a geometry, but the outside world insists. */
  355   entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
  356   entry->heads = 64;
  357   entry->sectors = 32;
  358 }
  359 

Cache object: bb69bc4f0707142cb5a9fe3defc36d2a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.