1 /* This file contains the device dependent part of the drivers for the
2 * following special files:
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
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)
19 #include <minix/drivers.h>
20 #include <minix/chardriver.h>
21 #include <minix/blockdriver.h>
22 #include <sys/ioc_memory.h>
25 #include <machine/param.h>
27 #include "kernel/const.h"
28 #include "kernel/config.h"
29 #include "kernel/type.h"
31 #include <machine/vm.h>
35 /* ramdisks (/dev/ram*) */
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
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 /*===========================================================================*
107 *===========================================================================*/
113 /* SEF local startup. */
116 /* The receive loop. */
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
);
124 chardriver_process(&m_cdtab
, CHARDRIVER_SYNC
, &msg
,
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. */
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. */
157 struct kinfo kinfo
; /* kernel information */
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.");
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
++) {
183 for(i
= 0; i
< NR_DEVS
; i
++)
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. */
195 /*===========================================================================*
197 *===========================================================================*/
198 static int m_is_block(dev_t minor
)
200 /* Return TRUE iff the given minor device number is for a block device. */
214 /*===========================================================================*
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
);
223 return(&m_geom
[device
]);
226 /*===========================================================================*
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;
243 unsigned long dv_size
;
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
];
261 /* How much to transfer and where to / from. */
262 count
= iov
->iov_size
;
263 grant
= (cp_grant_id_t
) iov
->iov_addr
;
267 /* No copying; ignore request. */
269 if (opcode
== DEV_GATHER_S
) return(OK
); /* always at EOF */
272 /* Virtual copying. For kernel memory. */
275 if(!dev_vaddr
|| dev_vaddr
== (vir_bytes
) MAP_FAILED
) {
276 printf("MEM: dev %d not initialized\n", m_device
);
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
);
285 r
=sys_safecopyfrom(endpt
, grant
, vir_offset
,
286 dev_vaddr
+ position
, count
);
289 panic("I/O copy failed: %d", r
);
293 /* Physical copying. Only used to access entire memory.
294 * Transfer one 'page window' at a time.
298 u32_t pagestart
, page_off
;
299 static u32_t pagestart_mapped
;
300 static int any_mapped
= 0;
306 if (position
>= dv_size
)
307 return(OK
); /* check for EOF */
308 if (position
+ count
> dv_size
)
309 count
= dv_size
- 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
) {
320 if(vm_unmap_phys(SELF
, vaddr
, PAGE_SIZE
) != OK
)
321 panic("vm_unmap_phys failed");
324 vaddr
= vm_map_phys(SELF
, (void *) pagestart
, PAGE_SIZE
);
325 if(vaddr
== MAP_FAILED
)
330 printf("memory: vm_map_phys failed\n");
334 pagestart_mapped
= pagestart
;
337 /* how much to be done within this page. */
338 subcount
= PAGE_SIZE
-page_off
;
342 if (opcode
== DEV_GATHER_S
) { /* copy data */
343 s
=sys_safecopyto(endpt
, grant
,
344 vir_offset
, (vir_bytes
) vaddr
+page_off
, subcount
);
346 s
=sys_safecopyfrom(endpt
, grant
,
347 vir_offset
, (vir_bytes
) vaddr
+page_off
, subcount
);
355 /* Null byte stream generator. */
357 if (opcode
== DEV_GATHER_S
) {
358 size_t suboffset
= 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
);
374 /* Book the number of bytes transferred. */
377 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
383 /*===========================================================================*
385 *===========================================================================*/
386 static int m_do_open(message
*m_ptr
)
388 /* Open a memory character device. */
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
);
399 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
400 m_ptr
->USER_ENDPT
, r
);
411 /*===========================================================================*
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
);
428 /*===========================================================================*
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 /*===========================================================================*
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. */
454 vir_bytes vir_offset
= 0;
456 unsigned long dv_size
;
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
);
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
);
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
);
489 r
=sys_safecopyfrom(endpt
, grant
, vir_offset
,
490 dev_vaddr
+ position
, count
);
493 panic("I/O copy failed: %d", r
);
496 /* Book the number of bytes transferred. */
500 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
506 /*===========================================================================*
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
);
519 /*===========================================================================*
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
);
536 /*===========================================================================*
538 *===========================================================================*/
539 static int m_block_ioctl(dev_t minor
, unsigned int request
, endpoint_t endpt
,
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.
552 if (request
!= MIOCRAMSIZE
)
555 if(minor
== IMGRD_DEV
)
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
);
568 /* Get request structure */
569 s
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
)&ramdev_size
,
570 sizeof(ramdev_size
));
575 if(m_vaddrs
[minor
] && !cmp64(dv
->dv_size
, cvul64(ramdev_size
))) {
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
]);
584 if(m_vaddrs
[minor
]) {
588 if(ex64hi(dv
->dv_size
)) {
589 panic("huge old ramdisk");
593 if((o
= a
% PAGE_SIZE
)) {
594 vir_bytes l
= PAGE_SIZE
- o
;
598 size
= rounddown(size
, PAGE_SIZE
);
599 r
= minix_munmap((void *) a
, size
);
601 printf("memory: WARNING: munmap failed: %d\n", r
);
603 m_vaddrs
[minor
] = (vir_bytes
) NULL
;
608 printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor
, ramdev_size
);
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");
621 m_vaddrs
[minor
] = (vir_bytes
) mem
;
623 dv
->dv_size
= cvul64(ramdev_size
);