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 #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 /*===========================================================================*
103 *===========================================================================*/
109 /* SEF local startup. */
112 /* The receive loop. */
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
);
120 chardriver_process(&m_cdtab
, CHARDRIVER_SYNC
, &msg
,
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. */
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. */
153 struct kinfo kinfo
; /* kernel information */
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.");
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
++)
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. */
186 /*===========================================================================*
188 *===========================================================================*/
189 static int m_is_block(dev_t minor
)
191 /* Return TRUE iff the given minor device number is for a block device. */
205 /*===========================================================================*
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
);
214 return(&m_geom
[device
]);
217 /*===========================================================================*
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. */
232 vir_bytes vir_offset
= 0;
234 unsigned long dv_size
;
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
];
252 /* How much to transfer and where to / from. */
253 count
= iov
->iov_size
;
254 grant
= (cp_grant_id_t
) iov
->iov_addr
;
258 /* No copying; ignore request. */
260 if (opcode
== DEV_GATHER_S
) return(OK
); /* always at EOF */
263 /* Virtual copying. For kernel memory. */
266 if(!dev_vaddr
|| dev_vaddr
== (vir_bytes
) MAP_FAILED
) {
267 printf("MEM: dev %d not initialized\n", m_device
);
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
);
276 r
=sys_safecopyfrom(endpt
, grant
, vir_offset
,
277 dev_vaddr
+ position
, count
);
280 panic("I/O copy failed: %d", r
);
284 /* Physical copying. Only used to access entire memory.
285 * Transfer one 'page window' at a time.
289 u32_t pagestart
, page_off
;
290 static u32_t pagestart_mapped
;
291 static int any_mapped
= 0;
297 if (position
>= dv_size
)
298 return(OK
); /* check for EOF */
299 if (position
+ count
> dv_size
)
300 count
= dv_size
- 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
) {
311 if(vm_unmap_phys(SELF
, vaddr
, PAGE_SIZE
) != OK
)
312 panic("vm_unmap_phys failed");
315 vaddr
= vm_map_phys(SELF
, (void *) pagestart
, PAGE_SIZE
);
316 if(vaddr
== MAP_FAILED
)
321 printf("memory: vm_map_phys failed\n");
325 pagestart_mapped
= pagestart
;
328 /* how much to be done within this page. */
329 subcount
= PAGE_SIZE
-page_off
;
333 if (opcode
== DEV_GATHER_S
) { /* copy data */
334 s
=sys_safecopyto(endpt
, grant
,
335 vir_offset
, (vir_bytes
) vaddr
+page_off
, subcount
);
337 s
=sys_safecopyfrom(endpt
, grant
,
338 vir_offset
, (vir_bytes
) vaddr
+page_off
, subcount
);
346 /* Null byte stream generator. */
348 if (opcode
== DEV_GATHER_S
)
349 if ((s
= sys_safememset(endpt
, grant
, 0, '\0', count
)) != OK
)
356 /* Book the number of bytes transferred. */
359 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
365 /*===========================================================================*
367 *===========================================================================*/
368 static int m_do_open(message
*m_ptr
)
370 /* Open a memory character device. */
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
);
381 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
382 m_ptr
->USER_ENDPT
, r
);
393 /*===========================================================================*
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
);
410 /*===========================================================================*
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 /*===========================================================================*
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. */
436 vir_bytes vir_offset
= 0;
438 unsigned long dv_size
;
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
);
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
);
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
);
471 r
=sys_safecopyfrom(endpt
, grant
, vir_offset
,
472 dev_vaddr
+ position
, count
);
475 panic("I/O copy failed: %d", r
);
478 /* Book the number of bytes transferred. */
482 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
488 /*===========================================================================*
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
);
501 /*===========================================================================*
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
);
518 /*===========================================================================*
520 *===========================================================================*/
521 static int m_block_ioctl(dev_t minor
, unsigned int request
, endpoint_t endpt
,
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.
534 if (request
!= MIOCRAMSIZE
)
537 if(minor
== IMGRD_DEV
)
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
);
550 /* Get request structure */
551 s
= sys_safecopyfrom(endpt
, grant
, 0, (vir_bytes
)&ramdev_size
,
552 sizeof(ramdev_size
));
557 if(m_vaddrs
[minor
] && !cmp64(dv
->dv_size
, cvul64(ramdev_size
))) {
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
]);
566 if(m_vaddrs
[minor
]) {
570 if(ex64hi(dv
->dv_size
)) {
571 panic("huge old ramdisk");
575 if((o
= a
% PAGE_SIZE
)) {
576 vir_bytes l
= PAGE_SIZE
- o
;
580 size
= rounddown(size
, PAGE_SIZE
);
581 r
= minix_munmap((void *) a
, size
);
583 printf("memory: WARNING: munmap failed: %d\n", r
);
585 m_vaddrs
[minor
] = (vir_bytes
) NULL
;
590 printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor
, ramdev_size
);
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");
603 m_vaddrs
[minor
] = (vir_bytes
) mem
;
605 dv
->dv_size
= cvul64(ramdev_size
);