memory: use sys_safememset() for /dev/zero
[minix.git] / drivers / memory / memory.c
blob4e8df02fe22cb570ef3a56d3fc7de5b7ab7d8d7f
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 * /dev/imgrd - boot image RAM disk
11 * Changes:
12 * Apr 29, 2005 added null byte generator (Jorrit N. Herder)
13 * Apr 09, 2005 added support for boot device (Jorrit N. Herder)
14 * Jul 26, 2004 moved RAM driver to user-space (Jorrit N. Herder)
15 * Apr 20, 1992 device dependent/independent split (Kees J. Bot)
18 #include <assert.h>
19 #include <minix/drivers.h>
20 #include <minix/chardriver.h>
21 #include <minix/blockdriver.h>
22 #include <sys/ioc_memory.h>
23 #include <minix/ds.h>
24 #include <minix/vm.h>
25 #include <machine/param.h>
26 #include <sys/mman.h>
27 #include "kernel/const.h"
28 #include "kernel/config.h"
29 #include "kernel/type.h"
31 #include <machine/vm.h>
33 #include "local.h"
35 /* ramdisks (/dev/ram*) */
36 #define RAMDISKS 6
38 #define RAM_DEV_LAST (RAM_DEV_FIRST+RAMDISKS-1)
40 #define NR_DEVS (7+RAMDISKS) /* number of minor devices */
42 static struct device m_geom[NR_DEVS]; /* base and size of each device */
43 static vir_bytes m_vaddrs[NR_DEVS];
44 static dev_t m_device; /* current minor character device */
46 static int openct[NR_DEVS];
48 static struct device *m_prepare(dev_t device);
49 static int m_transfer(endpoint_t endpt, int opcode, u64_t position,
50 iovec_t *iov, unsigned int nr_req, endpoint_t user_endpt, unsigned int
51 flags);
52 static int m_do_open(message *m_ptr);
53 static int m_do_close(message *m_ptr);
55 static struct device *m_block_part(dev_t minor);
56 static int m_block_transfer(dev_t minor, int do_write, u64_t position,
57 endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags);
58 static int m_block_open(dev_t minor, int access);
59 static int m_block_close(dev_t minor);
60 static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t
61 endpt, cp_grant_id_t grant);
63 /* Entry points to the CHARACTER part of this driver. */
64 static struct chardriver m_cdtab = {
65 m_do_open, /* open or mount */
66 m_do_close, /* nothing on a close */
67 nop_ioctl, /* no I/O control */
68 m_prepare, /* prepare for I/O on a given minor device */
69 m_transfer, /* do the I/O */
70 nop_cleanup, /* no need to clean up */
71 nop_alarm, /* no alarms */
72 nop_cancel, /* no blocking operations */
73 nop_select, /* select not supported */
74 NULL /* other messages not supported */
77 /* Entry points to the BLOCK part of this driver. */
78 static struct blockdriver m_bdtab = {
79 BLOCKDRIVER_TYPE_DISK,/* handle partition requests */
80 m_block_open, /* open or mount */
81 m_block_close, /* nothing on a close */
82 m_block_transfer, /* do the I/O */
83 m_block_ioctl, /* ram disk I/O control */
84 NULL, /* no need to clean up */
85 m_block_part, /* return partition information */
86 NULL, /* no geometry */
87 NULL, /* no interrupt processing */
88 NULL, /* no alarm processing */
89 NULL, /* no processing of other messages */
90 NULL /* no threading support */
93 #define click_to_round_k(n) \
94 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
96 /* SEF functions and variables. */
97 static void sef_local_startup(void);
98 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
101 /*===========================================================================*
102 * main *
103 *===========================================================================*/
104 int main(void)
106 message msg;
107 int r, ipc_status;
109 /* SEF local startup. */
110 sef_local_startup();
112 /* The receive loop. */
113 for (;;) {
114 if ((r = driver_receive(ANY, &msg, &ipc_status)) != OK)
115 panic("memory: driver_receive failed (%d)", r);
117 if (IS_BDEV_RQ(msg.m_type))
118 blockdriver_process(&m_bdtab, &msg, ipc_status);
119 else
120 chardriver_process(&m_cdtab, CHARDRIVER_SYNC, &msg,
121 ipc_status);
124 return(OK);
127 /*===========================================================================*
128 * sef_local_startup *
129 *===========================================================================*/
130 static void sef_local_startup()
132 /* Register init callbacks. */
133 sef_setcb_init_fresh(sef_cb_init_fresh);
134 sef_setcb_init_lu(sef_cb_init_fresh);
135 sef_setcb_init_restart(sef_cb_init_fresh);
137 /* Register live update callbacks. */
138 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
139 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
141 /* Let SEF perform startup. */
142 sef_startup();
145 /*===========================================================================*
146 * sef_cb_init_fresh *
147 *===========================================================================*/
148 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
150 /* Initialize the memory driver. */
151 int i;
152 #if 0
153 struct kinfo kinfo; /* kernel information */
154 int s;
156 if (OK != (s=sys_getkinfo(&kinfo))) {
157 panic("Couldn't get kernel information: %d", s);
160 /* Map in kernel memory for /dev/kmem. */
161 m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
162 m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
163 if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base,
164 kinfo.kmem_size)) == MAP_FAILED) {
165 printf("MEM: Couldn't map in /dev/kmem.");
167 #endif
169 /* Ramdisk image built into the memory driver */
170 m_geom[IMGRD_DEV].dv_base= cvul64(0);
171 m_geom[IMGRD_DEV].dv_size= cvul64(imgrd_size);
172 m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd;
174 for(i = 0; i < NR_DEVS; i++)
175 openct[i] = 0;
177 /* Set up memory range for /dev/mem. */
178 m_geom[MEM_DEV].dv_base = cvul64(0);
179 m_geom[MEM_DEV].dv_size = cvul64(0xffffffff);
181 m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */
183 return(OK);
186 /*===========================================================================*
187 * m_is_block *
188 *===========================================================================*/
189 static int m_is_block(dev_t minor)
191 /* Return TRUE iff the given minor device number is for a block device. */
193 switch (minor) {
194 case MEM_DEV:
195 case KMEM_DEV:
196 case NULL_DEV:
197 case ZERO_DEV:
198 return FALSE;
200 default:
201 return TRUE;
205 /*===========================================================================*
206 * m_prepare *
207 *===========================================================================*/
208 static struct device *m_prepare(dev_t device)
210 /* Prepare for I/O on a device: check if the minor device number is ok. */
211 if (device >= NR_DEVS || m_is_block(device)) return(NULL);
212 m_device = device;
214 return(&m_geom[device]);
217 /*===========================================================================*
218 * m_transfer *
219 *===========================================================================*/
220 static int m_transfer(
221 endpoint_t endpt, /* endpoint of grant owner */
222 int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */
223 u64_t pos64, /* offset on device to read or write */
224 iovec_t *iov, /* pointer to read or write request vector */
225 unsigned int nr_req, /* length of request vector */
226 endpoint_t UNUSED(user_endpt),/* endpoint of user process */
227 unsigned int UNUSED(flags)
230 /* Read or write one the driver's character devices. */
231 unsigned count;
232 vir_bytes vir_offset = 0;
233 struct device *dv;
234 unsigned long dv_size;
235 int s, r;
236 off_t position;
237 cp_grant_id_t grant;
238 vir_bytes dev_vaddr;
240 /* ZERO_DEV and NULL_DEV are infinite in size. */
241 if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0)
242 return OK; /* Beyond EOF */
243 position= cv64ul(pos64);
245 /* Get minor device number and check for /dev/null. */
246 dv = &m_geom[m_device];
247 dv_size = cv64ul(dv->dv_size);
248 dev_vaddr = m_vaddrs[m_device];
250 while (nr_req > 0) {
252 /* How much to transfer and where to / from. */
253 count = iov->iov_size;
254 grant = (cp_grant_id_t) iov->iov_addr;
256 switch (m_device) {
258 /* No copying; ignore request. */
259 case NULL_DEV:
260 if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */
261 break;
263 /* Virtual copying. For kernel memory. */
264 default:
265 case KMEM_DEV:
266 if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
267 printf("MEM: dev %d not initialized\n", m_device);
268 return EIO;
270 if (position >= dv_size) return(OK); /* check for EOF */
271 if (position + count > dv_size) count = dv_size - position;
272 if (opcode == DEV_GATHER_S) { /* copy actual data */
273 r=sys_safecopyto(endpt, grant, vir_offset,
274 dev_vaddr + position, count);
275 } else {
276 r=sys_safecopyfrom(endpt, grant, vir_offset,
277 dev_vaddr + position, count);
279 if(r != OK) {
280 panic("I/O copy failed: %d", r);
282 break;
284 /* Physical copying. Only used to access entire memory.
285 * Transfer one 'page window' at a time.
287 case MEM_DEV:
289 u32_t pagestart, page_off;
290 static u32_t pagestart_mapped;
291 static int any_mapped = 0;
292 static char *vaddr;
293 int r;
294 u32_t subcount;
295 phys_bytes mem_phys;
297 if (position >= dv_size)
298 return(OK); /* check for EOF */
299 if (position + count > dv_size)
300 count = dv_size - position;
301 mem_phys = position;
303 page_off = mem_phys % PAGE_SIZE;
304 pagestart = mem_phys - page_off;
306 /* All memory to the map call has to be page-aligned.
307 * Don't have to map same page over and over.
309 if(!any_mapped || pagestart_mapped != pagestart) {
310 if(any_mapped) {
311 if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK)
312 panic("vm_unmap_phys failed");
313 any_mapped = 0;
315 vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE);
316 if(vaddr == MAP_FAILED)
317 r = ENOMEM;
318 else
319 r = OK;
320 if(r != OK) {
321 printf("memory: vm_map_phys failed\n");
322 return r;
324 any_mapped = 1;
325 pagestart_mapped = pagestart;
328 /* how much to be done within this page. */
329 subcount = PAGE_SIZE-page_off;
330 if(subcount > count)
331 subcount = count;
333 if (opcode == DEV_GATHER_S) { /* copy data */
334 s=sys_safecopyto(endpt, grant,
335 vir_offset, (vir_bytes) vaddr+page_off, subcount);
336 } else {
337 s=sys_safecopyfrom(endpt, grant,
338 vir_offset, (vir_bytes) vaddr+page_off, subcount);
340 if(s != OK)
341 return s;
342 count = subcount;
343 break;
346 /* Null byte stream generator. */
347 case ZERO_DEV:
348 if (opcode == DEV_GATHER_S)
349 if ((s = sys_safememset(endpt, grant, 0, '\0', count)) != OK)
350 return s;
352 break;
356 /* Book the number of bytes transferred. */
357 position += count;
358 vir_offset += count;
359 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
362 return(OK);
365 /*===========================================================================*
366 * m_do_open *
367 *===========================================================================*/
368 static int m_do_open(message *m_ptr)
370 /* Open a memory character device. */
371 int r;
373 /* Check device number on open. */
374 if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
375 #if defined(__i386__)
376 if (m_device == MEM_DEV)
378 r = sys_enable_iop(m_ptr->USER_ENDPT);
379 if (r != OK)
381 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
382 m_ptr->USER_ENDPT, r);
383 return r;
386 #endif
388 openct[m_device]++;
390 return(OK);
393 /*===========================================================================*
394 * m_do_close *
395 *===========================================================================*/
396 static int m_do_close(message *m_ptr)
398 /* Close a memory character device. */
399 if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
401 if(openct[m_device] < 1) {
402 printf("MEMORY: closing unopened device %d\n", m_device);
403 return(EINVAL);
405 openct[m_device]--;
407 return(OK);
410 /*===========================================================================*
411 * m_block_part *
412 *===========================================================================*/
413 static struct device *m_block_part(dev_t minor)
415 /* Prepare for I/O on a device: check if the minor device number is ok. */
416 if (minor >= NR_DEVS || !m_is_block(minor)) return(NULL);
418 return(&m_geom[minor]);
421 /*===========================================================================*
422 * m_block_transfer *
423 *===========================================================================*/
424 static int m_block_transfer(
425 dev_t minor, /* minor device number */
426 int do_write, /* read or write? */
427 u64_t pos64, /* offset on device to read or write */
428 endpoint_t endpt, /* process doing the request */
429 iovec_t *iov, /* pointer to read or write request vector */
430 unsigned int nr_req, /* length of request vector */
431 int UNUSED(flags) /* transfer flags */
434 /* Read or write one the driver's block devices. */
435 unsigned count;
436 vir_bytes vir_offset = 0;
437 struct device *dv;
438 unsigned long dv_size;
439 int r;
440 off_t position;
441 vir_bytes dev_vaddr;
442 cp_grant_id_t grant;
443 ssize_t total = 0;
445 /* Get minor device information. */
446 if ((dv = m_block_part(minor)) == NULL) return(ENXIO);
447 dv_size = cv64ul(dv->dv_size);
448 dev_vaddr = m_vaddrs[minor];
450 if (ex64hi(pos64) != 0)
451 return OK; /* Beyond EOF */
452 position= cv64ul(pos64);
454 while (nr_req > 0) {
456 /* How much to transfer and where to / from. */
457 count = iov->iov_size;
458 grant = (cp_grant_id_t) iov->iov_addr;
460 /* Virtual copying. For RAM disks and internal FS. */
461 if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
462 printf("MEM: dev %d not initialized\n", minor);
463 return EIO;
465 if (position >= dv_size) return(total); /* check for EOF */
466 if (position + count > dv_size) count = dv_size - position;
467 if (!do_write) { /* copy actual data */
468 r=sys_safecopyto(endpt, grant, vir_offset,
469 dev_vaddr + position, count);
470 } else {
471 r=sys_safecopyfrom(endpt, grant, vir_offset,
472 dev_vaddr + position, count);
474 if(r != OK) {
475 panic("I/O copy failed: %d", r);
478 /* Book the number of bytes transferred. */
479 position += count;
480 vir_offset += count;
481 total += count;
482 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
485 return(total);
488 /*===========================================================================*
489 * m_block_open *
490 *===========================================================================*/
491 static int m_block_open(dev_t minor, int UNUSED(access))
493 /* Open a memory block device. */
494 if (m_block_part(minor) == NULL) return(ENXIO);
496 openct[minor]++;
498 return(OK);
501 /*===========================================================================*
502 * m_block_close *
503 *===========================================================================*/
504 static int m_block_close(dev_t minor)
506 /* Close a memory block device. */
507 if (m_block_part(minor) == NULL) return(ENXIO);
509 if(openct[minor] < 1) {
510 printf("MEMORY: closing unopened device %d\n", minor);
511 return(EINVAL);
513 openct[minor]--;
515 return(OK);
518 /*===========================================================================*
519 * m_block_ioctl *
520 *===========================================================================*/
521 static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
522 cp_grant_id_t grant)
524 /* I/O controls for the block devices of the memory driver. Currently there is
525 * one I/O control specific to the memory driver:
526 * - MIOCRAMSIZE: to set the size of the RAM disk.
528 struct device *dv;
529 u32_t ramdev_size;
530 int s;
531 void *mem;
532 int is_imgrd = 0;
534 if (request != MIOCRAMSIZE)
535 return EINVAL;
537 if(minor == IMGRD_DEV)
538 is_imgrd = 1;
540 /* Someone wants to create a new RAM disk with the given size.
541 * A ramdisk can be created only once, and only on RAM disk device.
543 if ((dv = m_block_part(minor)) == NULL) return ENXIO;
544 if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) &&
545 minor != RAM_DEV_OLD && !is_imgrd) {
546 printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor);
547 return EINVAL;
550 /* Get request structure */
551 s= sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&ramdev_size,
552 sizeof(ramdev_size));
553 if (s != OK)
554 return s;
555 if(is_imgrd)
556 ramdev_size = 0;
557 if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) {
558 return(OK);
560 /* openct is 1 for the ioctl(). */
561 if(openct[minor] != 1) {
562 printf("MEM: MIOCRAMSIZE: %d in use (count %d)\n",
563 minor, openct[minor]);
564 return(EBUSY);
566 if(m_vaddrs[minor]) {
567 u32_t a, o;
568 u64_t size;
569 int r;
570 if(ex64hi(dv->dv_size)) {
571 panic("huge old ramdisk");
573 size = dv->dv_size;
574 a = m_vaddrs[minor];
575 if((o = a % PAGE_SIZE)) {
576 vir_bytes l = PAGE_SIZE - o;
577 a += l;
578 size -= l;
580 size = rounddown(size, PAGE_SIZE);
581 r = minix_munmap((void *) a, size);
582 if(r != OK) {
583 printf("memory: WARNING: munmap failed: %d\n", r);
585 m_vaddrs[minor] = (vir_bytes) NULL;
586 dv->dv_size = 0;
589 #if DEBUG
590 printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size);
591 #endif
593 mem = NULL;
595 /* Try to allocate a piece of memory for the RAM disk. */
596 if(ramdev_size > 0 &&
597 (mem = minix_mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE,
598 MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) {
599 printf("MEM: failed to get memory for ramdisk\n");
600 return(ENOMEM);
603 m_vaddrs[minor] = (vir_bytes) mem;
605 dv->dv_size = cvul64(ramdev_size);
607 return(OK);