VM: full munmap
[minix.git] / drivers / memory / memory.c
bloba5f3a6cea523e54328466bb4e1861e8872d132fc
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 /* Buffer for the /dev/zero null byte feed. */
94 #define ZERO_BUF_SIZE 1024
95 static char dev_zero[ZERO_BUF_SIZE];
97 #define click_to_round_k(n) \
98 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
100 /* SEF functions and variables. */
101 static void sef_local_startup(void);
102 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
105 /*===========================================================================*
106 * main *
107 *===========================================================================*/
108 int main(void)
110 message msg;
111 int r, ipc_status;
113 /* SEF local startup. */
114 sef_local_startup();
116 /* The receive loop. */
117 for (;;) {
118 if ((r = driver_receive(ANY, &msg, &ipc_status)) != OK)
119 panic("memory: driver_receive failed (%d)", r);
121 if (IS_BDEV_RQ(msg.m_type))
122 blockdriver_process(&m_bdtab, &msg, ipc_status);
123 else
124 chardriver_process(&m_cdtab, CHARDRIVER_SYNC, &msg,
125 ipc_status);
128 return(OK);
131 /*===========================================================================*
132 * sef_local_startup *
133 *===========================================================================*/
134 static void sef_local_startup()
136 /* Register init callbacks. */
137 sef_setcb_init_fresh(sef_cb_init_fresh);
138 sef_setcb_init_lu(sef_cb_init_fresh);
139 sef_setcb_init_restart(sef_cb_init_fresh);
141 /* Register live update callbacks. */
142 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
143 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
145 /* Let SEF perform startup. */
146 sef_startup();
149 /*===========================================================================*
150 * sef_cb_init_fresh *
151 *===========================================================================*/
152 static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
154 /* Initialize the memory driver. */
155 int i;
156 #if 0
157 struct kinfo kinfo; /* kernel information */
158 int s;
160 if (OK != (s=sys_getkinfo(&kinfo))) {
161 panic("Couldn't get kernel information: %d", s);
164 /* Map in kernel memory for /dev/kmem. */
165 m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
166 m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
167 if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base,
168 kinfo.kmem_size)) == MAP_FAILED) {
169 printf("MEM: Couldn't map in /dev/kmem.");
171 #endif
173 /* Ramdisk image built into the memory driver */
174 m_geom[IMGRD_DEV].dv_base= cvul64(0);
175 m_geom[IMGRD_DEV].dv_size= cvul64(imgrd_size);
176 m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd;
178 /* Initialize /dev/zero. Simply write zeros into the buffer. */
179 for (i=0; i<ZERO_BUF_SIZE; i++) {
180 dev_zero[i] = '\0';
183 for(i = 0; i < NR_DEVS; i++)
184 openct[i] = 0;
186 /* Set up memory range for /dev/mem. */
187 m_geom[MEM_DEV].dv_base = cvul64(0);
188 m_geom[MEM_DEV].dv_size = cvul64(0xffffffff);
190 m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */
192 return(OK);
195 /*===========================================================================*
196 * m_is_block *
197 *===========================================================================*/
198 static int m_is_block(dev_t minor)
200 /* Return TRUE iff the given minor device number is for a block device. */
202 switch (minor) {
203 case MEM_DEV:
204 case KMEM_DEV:
205 case NULL_DEV:
206 case ZERO_DEV:
207 return FALSE;
209 default:
210 return TRUE;
214 /*===========================================================================*
215 * m_prepare *
216 *===========================================================================*/
217 static struct device *m_prepare(dev_t device)
219 /* Prepare for I/O on a device: check if the minor device number is ok. */
220 if (device >= NR_DEVS || m_is_block(device)) return(NULL);
221 m_device = device;
223 return(&m_geom[device]);
226 /*===========================================================================*
227 * m_transfer *
228 *===========================================================================*/
229 static int m_transfer(
230 endpoint_t endpt, /* endpoint of grant owner */
231 int opcode, /* DEV_GATHER_S or DEV_SCATTER_S */
232 u64_t pos64, /* offset on device to read or write */
233 iovec_t *iov, /* pointer to read or write request vector */
234 unsigned int nr_req, /* length of request vector */
235 endpoint_t UNUSED(user_endpt),/* endpoint of user process */
236 unsigned int UNUSED(flags)
239 /* Read or write one the driver's character devices. */
240 unsigned count, left, chunk;
241 vir_bytes vir_offset = 0;
242 struct device *dv;
243 unsigned long dv_size;
244 int s, r;
245 off_t position;
246 cp_grant_id_t grant;
247 vir_bytes dev_vaddr;
249 /* ZERO_DEV and NULL_DEV are infinite in size. */
250 if (m_device != ZERO_DEV && m_device != NULL_DEV && ex64hi(pos64) != 0)
251 return OK; /* Beyond EOF */
252 position= cv64ul(pos64);
254 /* Get minor device number and check for /dev/null. */
255 dv = &m_geom[m_device];
256 dv_size = cv64ul(dv->dv_size);
257 dev_vaddr = m_vaddrs[m_device];
259 while (nr_req > 0) {
261 /* How much to transfer and where to / from. */
262 count = iov->iov_size;
263 grant = (cp_grant_id_t) iov->iov_addr;
265 switch (m_device) {
267 /* No copying; ignore request. */
268 case NULL_DEV:
269 if (opcode == DEV_GATHER_S) return(OK); /* always at EOF */
270 break;
272 /* Virtual copying. For kernel memory. */
273 default:
274 case KMEM_DEV:
275 if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
276 printf("MEM: dev %d not initialized\n", m_device);
277 return EIO;
279 if (position >= dv_size) return(OK); /* check for EOF */
280 if (position + count > dv_size) count = dv_size - position;
281 if (opcode == DEV_GATHER_S) { /* copy actual data */
282 r=sys_safecopyto(endpt, grant, vir_offset,
283 dev_vaddr + position, count);
284 } else {
285 r=sys_safecopyfrom(endpt, grant, vir_offset,
286 dev_vaddr + position, count);
288 if(r != OK) {
289 panic("I/O copy failed: %d", r);
291 break;
293 /* Physical copying. Only used to access entire memory.
294 * Transfer one 'page window' at a time.
296 case MEM_DEV:
298 u32_t pagestart, page_off;
299 static u32_t pagestart_mapped;
300 static int any_mapped = 0;
301 static char *vaddr;
302 int r;
303 u32_t subcount;
304 phys_bytes mem_phys;
306 if (position >= dv_size)
307 return(OK); /* check for EOF */
308 if (position + count > dv_size)
309 count = dv_size - position;
310 mem_phys = position;
312 page_off = mem_phys % PAGE_SIZE;
313 pagestart = mem_phys - page_off;
315 /* All memory to the map call has to be page-aligned.
316 * Don't have to map same page over and over.
318 if(!any_mapped || pagestart_mapped != pagestart) {
319 if(any_mapped) {
320 if(vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK)
321 panic("vm_unmap_phys failed");
322 any_mapped = 0;
324 vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE);
325 if(vaddr == MAP_FAILED)
326 r = ENOMEM;
327 else
328 r = OK;
329 if(r != OK) {
330 printf("memory: vm_map_phys failed\n");
331 return r;
333 any_mapped = 1;
334 pagestart_mapped = pagestart;
337 /* how much to be done within this page. */
338 subcount = PAGE_SIZE-page_off;
339 if(subcount > count)
340 subcount = count;
342 if (opcode == DEV_GATHER_S) { /* copy data */
343 s=sys_safecopyto(endpt, grant,
344 vir_offset, (vir_bytes) vaddr+page_off, subcount);
345 } else {
346 s=sys_safecopyfrom(endpt, grant,
347 vir_offset, (vir_bytes) vaddr+page_off, subcount);
349 if(s != OK)
350 return s;
351 count = subcount;
352 break;
355 /* Null byte stream generator. */
356 case ZERO_DEV:
357 if (opcode == DEV_GATHER_S) {
358 size_t suboffset = 0;
359 left = count;
360 while (left > 0) {
361 chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE : left;
362 s=sys_safecopyto(endpt, grant,
363 vir_offset+suboffset, (vir_bytes) dev_zero, chunk);
364 if(s != OK)
365 return s;
366 left -= chunk;
367 suboffset += chunk;
370 break;
374 /* Book the number of bytes transferred. */
375 position += count;
376 vir_offset += count;
377 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
380 return(OK);
383 /*===========================================================================*
384 * m_do_open *
385 *===========================================================================*/
386 static int m_do_open(message *m_ptr)
388 /* Open a memory character device. */
389 int r;
391 /* Check device number on open. */
392 if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
393 #if defined(__i386__)
394 if (m_device == MEM_DEV)
396 r = sys_enable_iop(m_ptr->USER_ENDPT);
397 if (r != OK)
399 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
400 m_ptr->USER_ENDPT, r);
401 return r;
404 #endif
406 openct[m_device]++;
408 return(OK);
411 /*===========================================================================*
412 * m_do_close *
413 *===========================================================================*/
414 static int m_do_close(message *m_ptr)
416 /* Close a memory character device. */
417 if (m_prepare(m_ptr->DEVICE) == NULL) return(ENXIO);
419 if(openct[m_device] < 1) {
420 printf("MEMORY: closing unopened device %d\n", m_device);
421 return(EINVAL);
423 openct[m_device]--;
425 return(OK);
428 /*===========================================================================*
429 * m_block_part *
430 *===========================================================================*/
431 static struct device *m_block_part(dev_t minor)
433 /* Prepare for I/O on a device: check if the minor device number is ok. */
434 if (minor >= NR_DEVS || !m_is_block(minor)) return(NULL);
436 return(&m_geom[minor]);
439 /*===========================================================================*
440 * m_block_transfer *
441 *===========================================================================*/
442 static int m_block_transfer(
443 dev_t minor, /* minor device number */
444 int do_write, /* read or write? */
445 u64_t pos64, /* offset on device to read or write */
446 endpoint_t endpt, /* process doing the request */
447 iovec_t *iov, /* pointer to read or write request vector */
448 unsigned int nr_req, /* length of request vector */
449 int UNUSED(flags) /* transfer flags */
452 /* Read or write one the driver's block devices. */
453 unsigned count;
454 vir_bytes vir_offset = 0;
455 struct device *dv;
456 unsigned long dv_size;
457 int r;
458 off_t position;
459 vir_bytes dev_vaddr;
460 cp_grant_id_t grant;
461 ssize_t total = 0;
463 /* Get minor device information. */
464 if ((dv = m_block_part(minor)) == NULL) return(ENXIO);
465 dv_size = cv64ul(dv->dv_size);
466 dev_vaddr = m_vaddrs[minor];
468 if (ex64hi(pos64) != 0)
469 return OK; /* Beyond EOF */
470 position= cv64ul(pos64);
472 while (nr_req > 0) {
474 /* How much to transfer and where to / from. */
475 count = iov->iov_size;
476 grant = (cp_grant_id_t) iov->iov_addr;
478 /* Virtual copying. For RAM disks and internal FS. */
479 if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) {
480 printf("MEM: dev %d not initialized\n", minor);
481 return EIO;
483 if (position >= dv_size) return(total); /* check for EOF */
484 if (position + count > dv_size) count = dv_size - position;
485 if (!do_write) { /* copy actual data */
486 r=sys_safecopyto(endpt, grant, vir_offset,
487 dev_vaddr + position, count);
488 } else {
489 r=sys_safecopyfrom(endpt, grant, vir_offset,
490 dev_vaddr + position, count);
492 if(r != OK) {
493 panic("I/O copy failed: %d", r);
496 /* Book the number of bytes transferred. */
497 position += count;
498 vir_offset += count;
499 total += count;
500 if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; }
503 return(total);
506 /*===========================================================================*
507 * m_block_open *
508 *===========================================================================*/
509 static int m_block_open(dev_t minor, int UNUSED(access))
511 /* Open a memory block device. */
512 if (m_block_part(minor) == NULL) return(ENXIO);
514 openct[minor]++;
516 return(OK);
519 /*===========================================================================*
520 * m_block_close *
521 *===========================================================================*/
522 static int m_block_close(dev_t minor)
524 /* Close a memory block device. */
525 if (m_block_part(minor) == NULL) return(ENXIO);
527 if(openct[minor] < 1) {
528 printf("MEMORY: closing unopened device %d\n", minor);
529 return(EINVAL);
531 openct[minor]--;
533 return(OK);
536 /*===========================================================================*
537 * m_block_ioctl *
538 *===========================================================================*/
539 static int m_block_ioctl(dev_t minor, unsigned int request, endpoint_t endpt,
540 cp_grant_id_t grant)
542 /* I/O controls for the block devices of the memory driver. Currently there is
543 * one I/O control specific to the memory driver:
544 * - MIOCRAMSIZE: to set the size of the RAM disk.
546 struct device *dv;
547 u32_t ramdev_size;
548 int s;
549 void *mem;
550 int is_imgrd = 0;
552 if (request != MIOCRAMSIZE)
553 return EINVAL;
555 if(minor == IMGRD_DEV)
556 is_imgrd = 1;
558 /* Someone wants to create a new RAM disk with the given size.
559 * A ramdisk can be created only once, and only on RAM disk device.
561 if ((dv = m_block_part(minor)) == NULL) return ENXIO;
562 if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) &&
563 minor != RAM_DEV_OLD && !is_imgrd) {
564 printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor);
565 return EINVAL;
568 /* Get request structure */
569 s= sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&ramdev_size,
570 sizeof(ramdev_size));
571 if (s != OK)
572 return s;
573 if(is_imgrd)
574 ramdev_size = 0;
575 if(m_vaddrs[minor] && !cmp64(dv->dv_size, cvul64(ramdev_size))) {
576 return(OK);
578 /* openct is 1 for the ioctl(). */
579 if(openct[minor] != 1) {
580 printf("MEM: MIOCRAMSIZE: %d in use (count %d)\n",
581 minor, openct[minor]);
582 return(EBUSY);
584 if(m_vaddrs[minor]) {
585 u32_t a, o;
586 u64_t size;
587 int r;
588 if(ex64hi(dv->dv_size)) {
589 panic("huge old ramdisk");
591 size = dv->dv_size;
592 a = m_vaddrs[minor];
593 if((o = a % PAGE_SIZE)) {
594 vir_bytes l = PAGE_SIZE - o;
595 a += l;
596 size -= l;
598 size = rounddown(size, PAGE_SIZE);
599 r = minix_munmap((void *) a, size);
600 if(r != OK) {
601 printf("memory: WARNING: munmap failed: %d\n", r);
603 m_vaddrs[minor] = (vir_bytes) NULL;
604 dv->dv_size = 0;
607 #if DEBUG
608 printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size);
609 #endif
611 mem = NULL;
613 /* Try to allocate a piece of memory for the RAM disk. */
614 if(ramdev_size > 0 &&
615 (mem = minix_mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE,
616 MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) {
617 printf("MEM: failed to get memory for ramdisk\n");
618 return(ENOMEM);
621 m_vaddrs[minor] = (vir_bytes) mem;
623 dv->dv_size = cvul64(ramdev_size);
625 return(OK);