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
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)
17 #include "../drivers.h"
18 #include "../libdriver/driver.h"
19 #include <sys/ioc_memory.h>
22 #include "../../kernel/const.h"
23 #include "../../kernel/config.h"
24 #include "../../kernel/type.h"
26 #define MY_DS_NAME_BASE "dev:memory:ramdisk_base"
27 #define MY_DS_NAME_SIZE "dev:memory:ramdisk_size"
35 #define NR_DEVS 7 /* number of minor devices */
37 PRIVATE
struct device m_geom
[NR_DEVS
]; /* base and size of each device */
38 PRIVATE
int m_seg
[NR_DEVS
]; /* segment index of each device */
39 PRIVATE
int m_device
; /* current device */
40 PRIVATE
struct kinfo kinfo
; /* kernel information */
42 extern int errno
; /* error number for PM calls */
44 FORWARD
_PROTOTYPE( char *m_name
, (void) );
45 FORWARD
_PROTOTYPE( struct device
*m_prepare
, (int device
) );
46 FORWARD
_PROTOTYPE( int m_transfer
, (int proc_nr
, int opcode
, u64_t position
,
47 iovec_t
*iov
, unsigned nr_req
, int safe
));
48 FORWARD
_PROTOTYPE( int m_do_open
, (struct driver
*dp
, message
*m_ptr
) );
49 FORWARD
_PROTOTYPE( void m_init
, (void) );
50 FORWARD
_PROTOTYPE( int m_ioctl
, (struct driver
*dp
, message
*m_ptr
, int safe
));
51 FORWARD
_PROTOTYPE( void m_geometry
, (struct partition
*entry
) );
53 /* Entry points to this driver. */
54 PRIVATE
struct driver m_dtab
= {
55 m_name
, /* current device's name */
56 m_do_open
, /* open or mount */
57 do_nop
, /* nothing on a close */
58 m_ioctl
, /* specify ram disk geometry */
59 m_prepare
, /* prepare for I/O on a given minor device */
60 m_transfer
, /* do the I/O */
61 nop_cleanup
, /* no need to clean up */
62 m_geometry
, /* memory device "geometry" */
63 nop_signal
, /* system signals */
71 /* One page of temporary mapping area - enough to be able to page-align
74 static char pagedata_buf
[2*PAGE_SIZE
];
75 vir_bytes pagedata_aligned
;
77 /* Buffer for the /dev/zero null byte feed. */
78 #define ZERO_BUF_SIZE 1024
79 PRIVATE
char dev_zero
[ZERO_BUF_SIZE
];
81 #define click_to_round_k(n) \
82 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
84 /*===========================================================================*
86 *===========================================================================*/
89 /* Main program. Initialize the memory driver and start the main loop. */
92 sa
.sa_handler
= SIG_MESS
;
93 sigemptyset(&sa
.sa_mask
);
95 if (sigaction(SIGTERM
,&sa
,NULL
)<0) panic("MEM","sigaction failed", errno
);
102 /*===========================================================================*
104 *===========================================================================*/
105 PRIVATE
char *m_name()
107 /* Return a name for the current device. */
108 static char name
[] = "memory";
112 /*===========================================================================*
114 *===========================================================================*/
115 PRIVATE
struct device
*m_prepare(device
)
118 /* Prepare for I/O on a device: check if the minor device number is ok. */
119 if (device
< 0 || device
>= NR_DEVS
) return(NIL_DEV
);
122 return(&m_geom
[device
]);
125 /*===========================================================================*
127 *===========================================================================*/
128 PRIVATE
int m_transfer(proc_nr
, opcode
, pos64
, iov
, nr_req
, safe
)
129 int proc_nr
; /* process doing the request */
130 int opcode
; /* DEV_GATHER_S or DEV_SCATTER_S */
131 u64_t pos64
; /* offset on device to read or write */
132 iovec_t
*iov
; /* pointer to read or write request vector */
133 unsigned nr_req
; /* length of request vector */
134 int safe
; /* safe copies */
136 /* Read or write one the driver's minor devices. */
139 unsigned count
, left
, chunk
;
140 vir_bytes user_vir
, vir_offset
= 0;
142 unsigned long dv_size
;
147 printf("m_transfer: unsafe?\n");
151 if (ex64hi(pos64
) != 0)
152 return OK
; /* Beyond EOF */
153 position
= cv64ul(pos64
);
155 /* Get minor device number and check for /dev/null. */
156 dv
= &m_geom
[m_device
];
157 dv_size
= cv64ul(dv
->dv_size
);
161 /* How much to transfer and where to / from. */
162 count
= iov
->iov_size
;
163 user_vir
= iov
->iov_addr
;
167 /* No copying; ignore request. */
169 if (opcode
== DEV_GATHER_S
) return(OK
); /* always at EOF */
172 /* Virtual copying. For RAM disk, kernel memory and boot device. */
176 if (position
>= dv_size
) return(OK
); /* check for EOF */
177 if (position
+ count
> dv_size
) count
= dv_size
- position
;
178 seg
= m_seg
[m_device
];
180 if (opcode
== DEV_GATHER_S
) { /* copy actual data */
181 r
=sys_safecopyto(proc_nr
, user_vir
, vir_offset
,
182 position
, count
, seg
);
184 r
=sys_safecopyfrom(proc_nr
, user_vir
, vir_offset
,
185 position
, count
, seg
);
188 panic("MEM","I/O copy failed",r
);
192 /* Physical copying. Only used to access entire memory.
193 * Transfer one 'page window' at a time.
197 u32_t pagestart
, page_off
;
198 static u32_t pagestart_mapped
;
199 static int any_mapped
= 0;
203 if (position
>= dv_size
)
204 return(OK
); /* check for EOF */
205 if (position
+ count
> dv_size
)
206 count
= dv_size
- position
;
207 mem_phys
= cv64ul(dv
->dv_base
) + position
;
209 page_off
= mem_phys
% PAGE_SIZE
;
210 pagestart
= mem_phys
- page_off
;
212 /* All memory to the map call has to be page-aligned.
213 * Don't have to map same page over and over.
215 if(!any_mapped
|| pagestart_mapped
!= pagestart
) {
216 if((r
=sys_vm_map(SELF
, 1, pagedata_aligned
,
217 PAGE_SIZE
, pagestart
)) != OK
) {
218 printf("memory: sys_vm_map failed: %d\n", r
);
222 pagestart_mapped
= pagestart
;
225 /* how much to be done within this page. */
226 subcount
= PAGE_SIZE
-page_off
;
230 if (opcode
== DEV_GATHER_S
) { /* copy data */
231 s
=sys_safecopyto(proc_nr
, user_vir
,
232 vir_offset
, pagedata_aligned
+page_off
, subcount
, D
);
234 s
=sys_safecopyfrom(proc_nr
, user_vir
,
235 vir_offset
, pagedata_aligned
+page_off
, subcount
, D
);
243 /* Null byte stream generator. */
245 if (opcode
== DEV_GATHER_S
) {
246 size_t suboffset
= 0;
249 chunk
= (left
> ZERO_BUF_SIZE
) ? ZERO_BUF_SIZE
: left
;
250 s
=sys_safecopyto(proc_nr
, user_vir
,
251 vir_offset
+suboffset
, (vir_bytes
) dev_zero
, chunk
, D
);
253 report("MEM","sys_safecopyto failed", s
);
261 if (position
>= dv_size
) return(OK
); /* check for EOF */
262 if (position
+ count
> dv_size
) count
= dv_size
- position
;
264 if (opcode
== DEV_GATHER_S
) { /* copy actual data */
265 s
=sys_safecopyto(proc_nr
, user_vir
, vir_offset
,
266 (vir_bytes
)&imgrd
[position
], count
, D
);
268 s
=sys_safecopyfrom(proc_nr
, user_vir
, vir_offset
,
269 (vir_bytes
)&imgrd
[position
], count
, D
);
273 /* Unknown (illegal) minor device. */
278 /* Book the number of bytes transferred. */
281 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
287 /*===========================================================================*
289 *===========================================================================*/
290 PRIVATE
int m_do_open(dp
, m_ptr
)
296 /* Check device number on open. */
297 if (m_prepare(m_ptr
->DEVICE
) == NIL_DEV
) return(ENXIO
);
298 if (m_device
== MEM_DEV
)
300 r
= sys_enable_iop(m_ptr
->IO_ENDPT
);
303 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
311 /*===========================================================================*
313 *===========================================================================*/
314 PRIVATE
void m_init()
316 /* Initialize this task. All minor devices are initialized one by one. */
321 if (OK
!= (s
=sys_getkinfo(&kinfo
))) {
322 panic("MEM","Couldn't get kernel information.",s
);
325 /* Install remote segment for /dev/kmem memory. */
326 m_geom
[KMEM_DEV
].dv_base
= cvul64(kinfo
.kmem_base
);
327 m_geom
[KMEM_DEV
].dv_size
= cvul64(kinfo
.kmem_size
);
328 if (OK
!= (s
=sys_segctl(&m_seg
[KMEM_DEV
], (u16_t
*) &s
, (vir_bytes
*) &s
,
329 kinfo
.kmem_base
, kinfo
.kmem_size
))) {
330 panic("MEM","Couldn't install remote segment.",s
);
333 /* Install remote segment for /dev/boot memory, if enabled. */
334 m_geom
[BOOT_DEV
].dv_base
= cvul64(kinfo
.bootdev_base
);
335 m_geom
[BOOT_DEV
].dv_size
= cvul64(kinfo
.bootdev_size
);
336 if (kinfo
.bootdev_base
> 0) {
337 if (OK
!= (s
=sys_segctl(&m_seg
[BOOT_DEV
], (u16_t
*) &s
, (vir_bytes
*) &s
,
338 kinfo
.bootdev_base
, kinfo
.bootdev_size
))) {
339 panic("MEM","Couldn't install remote segment.",s
);
343 /* See if there are already RAM disk details at the Data Store server. */
344 if(ds_retrieve_u32(MY_DS_NAME_BASE
, &ramdev_base
) == OK
&&
345 ds_retrieve_u32(MY_DS_NAME_SIZE
, &ramdev_size
) == OK
) {
346 printf("MEM retrieved size %u and base %u from DS, status %d\n",
347 ramdev_size
, ramdev_base
, s
);
348 if (OK
!= (s
=sys_segctl(&m_seg
[RAM_DEV
], (u16_t
*) &s
,
349 (vir_bytes
*) &s
, ramdev_base
, ramdev_size
))) {
350 panic("MEM","Couldn't install remote segment.",s
);
352 m_geom
[RAM_DEV
].dv_base
= cvul64(ramdev_base
);
353 m_geom
[RAM_DEV
].dv_size
= cvul64(ramdev_size
);
354 printf("MEM stored retrieved details as new RAM disk\n");
357 /* Ramdisk image built into the memory driver */
358 m_geom
[IMGRD_DEV
].dv_base
= cvul64(0);
359 m_geom
[IMGRD_DEV
].dv_size
= cvul64(imgrd_size
);
361 /* Initialize /dev/zero. Simply write zeros into the buffer. */
362 for (i
=0; i
<ZERO_BUF_SIZE
; i
++) {
366 /* Page-align page pointer. */
367 pagedata_aligned
= (u32_t
) pagedata_buf
+ PAGE_SIZE
;
368 pagedata_aligned
-= pagedata_aligned
% PAGE_SIZE
;
370 /* Set up memory range for /dev/mem. */
371 m_geom
[MEM_DEV
].dv_size
= cvul64(0xffffffff);
374 /*===========================================================================*
376 *===========================================================================*/
377 PRIVATE
int m_ioctl(dp
, m_ptr
, safe
)
378 struct driver
*dp
; /* pointer to driver structure */
379 message
*m_ptr
; /* pointer to control message */
382 /* I/O controls for the memory driver. Currently there is one I/O control:
383 * - MIOCRAMSIZE: to set the size of the RAM disk.
388 printf("m_transfer: unsafe?\n");
392 switch (m_ptr
->REQUEST
) {
394 /* Someone wants to create a new RAM disk with the given size. */
395 static int first_time
= 1;
398 phys_bytes ramdev_base
;
401 /* A ramdisk can be created only once, and only on RAM disk device. */
402 if (!first_time
) return(EPERM
);
403 if (m_ptr
->DEVICE
!= RAM_DEV
) return(EINVAL
);
404 if ((dv
= m_prepare(m_ptr
->DEVICE
)) == NIL_DEV
) return(ENXIO
);
407 ramdev_size
= m_ptr
->POSITION
;
409 /* Get request structure */
410 s
= sys_safecopyfrom(m_ptr
->IO_ENDPT
, (vir_bytes
)m_ptr
->IO_GRANT
,
411 0, (vir_bytes
)&ramdev_size
, sizeof(ramdev_size
), D
);
417 printf("allocating ramdisk of size 0x%x\n", ramdev_size
);
420 /* Try to allocate a piece of memory for the RAM disk. */
421 if (allocmem(ramdev_size
, &ramdev_base
) < 0) {
422 report("MEM", "warning, allocmem failed", errno
);
426 /* Store the values we got in the data store so we can retrieve
427 * them later on, in the unfortunate event of a crash.
429 if(ds_publish_u32(MY_DS_NAME_BASE
, ramdev_base
) != OK
||
430 ds_publish_u32(MY_DS_NAME_SIZE
, ramdev_size
) != OK
) {
431 panic("MEM","Couldn't store RAM disk details at DS.",s
);
435 printf("MEM stored size %u and base %u at DS, names %s and %s\n",
436 ramdev_size
, ramdev_base
, MY_DS_NAME_BASE
, MY_DS_NAME_SIZE
);
439 if (OK
!= (s
=sys_segctl(&m_seg
[RAM_DEV
], (u16_t
*) &s
,
440 (vir_bytes
*) &s
, ramdev_base
, ramdev_size
))) {
441 panic("MEM","Couldn't install remote segment.",s
);
444 dv
->dv_base
= cvul64(ramdev_base
);
445 dv
->dv_size
= cvul64(ramdev_size
);
452 struct mapreq mapreq
;
454 if ((*dp
->dr_prepare
)(m_ptr
->DEVICE
) == NIL_DEV
) return(ENXIO
);
455 if (m_device
!= MEM_DEV
)
458 do_map
= (m_ptr
->REQUEST
== MIOCMAP
); /* else unmap */
460 /* Get request structure */
461 r
= sys_safecopyfrom(m_ptr
->IO_ENDPT
, (vir_bytes
)m_ptr
->IO_GRANT
,
462 0, (vir_bytes
)&mapreq
, sizeof(mapreq
), D
);
466 r
= sys_vm_map(m_ptr
->IO_ENDPT
, do_map
,
467 (phys_bytes
)mapreq
.base
, mapreq
.size
, mapreq
.offset
);
472 return(do_diocntl(&m_dtab
, m_ptr
, safe
));
477 /*===========================================================================*
479 *===========================================================================*/
480 PRIVATE
void m_geometry(entry
)
481 struct partition
*entry
;
483 /* Memory devices don't have a geometry, but the outside world insists. */
484 entry
->cylinders
= div64u(m_geom
[m_device
].dv_size
, SECTOR_SIZE
) / (64 * 32);