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 */
41 PRIVATE
struct machine machine
; /* machine information */
43 extern int errno
; /* error number for PM calls */
45 FORWARD
_PROTOTYPE( char *m_name
, (void) );
46 FORWARD
_PROTOTYPE( struct device
*m_prepare
, (int device
) );
47 FORWARD
_PROTOTYPE( int m_transfer
, (int proc_nr
, int opcode
, u64_t position
,
48 iovec_t
*iov
, unsigned nr_req
, int safe
));
49 FORWARD
_PROTOTYPE( int m_do_open
, (struct driver
*dp
, message
*m_ptr
) );
50 FORWARD
_PROTOTYPE( void m_init
, (void) );
51 FORWARD
_PROTOTYPE( int m_ioctl
, (struct driver
*dp
, message
*m_ptr
, int safe
));
52 FORWARD
_PROTOTYPE( void m_geometry
, (struct partition
*entry
) );
54 /* Entry points to this driver. */
55 PRIVATE
struct driver m_dtab
= {
56 m_name
, /* current device's name */
57 m_do_open
, /* open or mount */
58 do_nop
, /* nothing on a close */
59 m_ioctl
, /* specify ram disk geometry */
60 m_prepare
, /* prepare for I/O on a given minor device */
61 m_transfer
, /* do the I/O */
62 nop_cleanup
, /* no need to clean up */
63 m_geometry
, /* memory device "geometry" */
64 nop_signal
, /* system signals */
72 /* Buffer for the /dev/zero null byte feed. */
73 #define ZERO_BUF_SIZE 1024
74 PRIVATE
char dev_zero
[ZERO_BUF_SIZE
];
76 #define click_to_round_k(n) \
77 ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
79 /*===========================================================================*
81 *===========================================================================*/
84 /* Main program. Initialize the memory driver and start the main loop. */
87 sa
.sa_handler
= SIG_MESS
;
88 sigemptyset(&sa
.sa_mask
);
90 if (sigaction(SIGTERM
,&sa
,NULL
)<0) panic("MEM","sigaction failed", errno
);
97 /*===========================================================================*
99 *===========================================================================*/
100 PRIVATE
char *m_name()
102 /* Return a name for the current device. */
103 static char name
[] = "memory";
107 /*===========================================================================*
109 *===========================================================================*/
110 PRIVATE
struct device
*m_prepare(device
)
113 /* Prepare for I/O on a device: check if the minor device number is ok. */
114 if (device
< 0 || device
>= NR_DEVS
) return(NIL_DEV
);
117 return(&m_geom
[device
]);
120 /*===========================================================================*
122 *===========================================================================*/
123 PRIVATE
int m_transfer(proc_nr
, opcode
, pos64
, iov
, nr_req
, safe
)
124 int proc_nr
; /* process doing the request */
125 int opcode
; /* DEV_GATHER_S or DEV_SCATTER_S */
126 u64_t pos64
; /* offset on device to read or write */
127 iovec_t
*iov
; /* pointer to read or write request vector */
128 unsigned nr_req
; /* length of request vector */
129 int safe
; /* safe copies */
131 /* Read or write one the driver's minor devices. */
134 unsigned count
, left
, chunk
;
135 vir_bytes user_vir
, vir_offset
= 0;
136 phys_bytes user_phys
;
138 unsigned long dv_size
;
145 printf("m_transfer: unsafe?\n");
149 if (ex64hi(pos64
) != 0)
150 return OK
; /* Beyond EOF */
151 position
= cv64ul(pos64
);
153 /* Get minor device number and check for /dev/null. */
154 dv
= &m_geom
[m_device
];
155 dv_size
= cv64ul(dv
->dv_size
);
159 /* How much to transfer and where to / from. */
160 count
= iov
->iov_size
;
161 user_vir
= iov
->iov_addr
;
165 /* No copying; ignore request. */
167 if (opcode
== DEV_GATHER_S
) return(OK
); /* always at EOF */
170 /* Virtual copying. For RAM disk, kernel memory and boot device. */
174 if (position
>= dv_size
) return(OK
); /* check for EOF */
175 if (position
+ count
> dv_size
) count
= dv_size
- position
;
176 seg
= m_seg
[m_device
];
178 if (opcode
== DEV_GATHER_S
) { /* copy actual data */
179 r
=sys_safecopyto(proc_nr
, user_vir
, vir_offset
,
180 position
, count
, seg
);
182 r
=sys_safecopyfrom(proc_nr
, user_vir
, vir_offset
,
183 position
, count
, seg
);
186 panic("MEM","I/O copy failed",r
);
190 /* Physical copying. Only used to access entire memory. */
192 if (position
>= dv_size
) {
193 printf("memory: read 0x%lx beyond physical memory of 0x%lx\n",
195 return(OK
); /* check for EOF */
197 if (position
+ count
> dv_size
) {
198 printf("memory: truncating count from %d to ", count
);
199 count
= dv_size
- position
;
200 printf("%d (size %d)\n", count
, dv_size
);
202 mem_phys
= cv64ul(dv
->dv_base
) + position
;
203 if((r
=sys_umap(proc_nr
, GRANT_SEG
, user_vir
,
204 count
+ vir_offset
, &user_phys
)) != OK
) {
205 panic("MEM","sys_umap failed in m_transfer",r
);
208 if (opcode
== DEV_GATHER_S
) { /* copy data */
209 sys_physcopy(NONE
, PHYS_SEG
, mem_phys
,
210 NONE
, PHYS_SEG
, user_phys
+ vir_offset
, count
);
212 sys_physcopy(NONE
, PHYS_SEG
, user_phys
+ vir_offset
,
213 NONE
, PHYS_SEG
, mem_phys
, count
);
217 /* Null byte stream generator. */
219 if (opcode
== DEV_GATHER_S
) {
220 size_t suboffset
= 0;
223 chunk
= (left
> ZERO_BUF_SIZE
) ? ZERO_BUF_SIZE
: left
;
224 s
=sys_safecopyto(proc_nr
, user_vir
,
225 vir_offset
+suboffset
, (vir_bytes
) dev_zero
, chunk
, D
);
227 report("MEM","sys_vircopy failed", s
);
235 if (position
>= dv_size
) return(OK
); /* check for EOF */
236 if (position
+ count
> dv_size
) count
= dv_size
- position
;
238 if (opcode
== DEV_GATHER_S
) { /* copy actual data */
239 s
=sys_safecopyto(proc_nr
, user_vir
, vir_offset
,
240 (vir_bytes
)&imgrd
[position
], count
, D
);
242 s
=sys_safecopyfrom(proc_nr
, user_vir
, vir_offset
,
243 (vir_bytes
)&imgrd
[position
], count
, D
);
247 /* Unknown (illegal) minor device. */
252 /* Book the number of bytes transferred. */
255 if ((iov
->iov_size
-= count
) == 0) { iov
++; nr_req
--; vir_offset
= 0; }
261 /*===========================================================================*
263 *===========================================================================*/
264 PRIVATE
int m_do_open(dp
, m_ptr
)
270 /* Check device number on open. */
271 if (m_prepare(m_ptr
->DEVICE
) == NIL_DEV
) return(ENXIO
);
272 if (m_device
== MEM_DEV
)
274 r
= sys_enable_iop(m_ptr
->IO_ENDPT
);
277 printf("m_do_open: sys_enable_iop failed for %d: %d\n",
285 /*===========================================================================*
287 *===========================================================================*/
288 PRIVATE
void m_init()
290 /* Initialize this task. All minor devices are initialized one by one. */
295 phys_bytes mem_top
= 0;
297 /* Physical memory, to check validity of /dev/mem access. */
298 #define MAX_MEM_RANGES 10
299 struct memory mem_chunks
[MAX_MEM_RANGES
];
301 if (OK
!= (s
=sys_getkinfo(&kinfo
))) {
302 panic("MEM","Couldn't get kernel information.",s
);
305 /* Obtain physical memory chunks for /dev/mem memory. */
306 if(env_memory_parse(mem_chunks
, MAX_MEM_RANGES
) != OK
)
307 printf("memory driver: no memory layout, /dev/mem won't work\n");
309 for(i
= 0; i
< MAX_MEM_RANGES
; i
++) {
311 top
= mem_chunks
[i
].base
+ mem_chunks
[i
].size
;
317 /* Install remote segment for /dev/kmem memory. */
318 m_geom
[KMEM_DEV
].dv_base
= cvul64(kinfo
.kmem_base
);
319 m_geom
[KMEM_DEV
].dv_size
= cvul64(kinfo
.kmem_size
);
320 if (OK
!= (s
=sys_segctl(&m_seg
[KMEM_DEV
], (u16_t
*) &s
, (vir_bytes
*) &s
,
321 kinfo
.kmem_base
, kinfo
.kmem_size
))) {
322 panic("MEM","Couldn't install remote segment.",s
);
325 /* Install remote segment for /dev/boot memory, if enabled. */
326 m_geom
[BOOT_DEV
].dv_base
= cvul64(kinfo
.bootdev_base
);
327 m_geom
[BOOT_DEV
].dv_size
= cvul64(kinfo
.bootdev_size
);
328 if (kinfo
.bootdev_base
> 0) {
329 if (OK
!= (s
=sys_segctl(&m_seg
[BOOT_DEV
], (u16_t
*) &s
, (vir_bytes
*) &s
,
330 kinfo
.bootdev_base
, kinfo
.bootdev_size
))) {
331 panic("MEM","Couldn't install remote segment.",s
);
335 /* See if there are already RAM disk details at the Data Store server. */
336 if(ds_retrieve_u32(MY_DS_NAME_BASE
, &ramdev_base
) == OK
&&
337 ds_retrieve_u32(MY_DS_NAME_SIZE
, &ramdev_size
) == OK
) {
338 printf("MEM retrieved size %u and base %u from DS, status %d\n",
339 ramdev_size
, ramdev_base
, s
);
340 if (OK
!= (s
=sys_segctl(&m_seg
[RAM_DEV
], (u16_t
*) &s
,
341 (vir_bytes
*) &s
, ramdev_base
, ramdev_size
))) {
342 panic("MEM","Couldn't install remote segment.",s
);
344 m_geom
[RAM_DEV
].dv_base
= cvul64(ramdev_base
);
345 m_geom
[RAM_DEV
].dv_size
= cvul64(ramdev_size
);
346 printf("MEM stored retrieved details as new RAM disk\n");
349 /* Ramdisk image built into the memory driver */
350 m_geom
[IMGRD_DEV
].dv_base
= cvul64(0);
351 m_geom
[IMGRD_DEV
].dv_size
= cvul64(imgrd_size
);
353 /* Initialize /dev/zero. Simply write zeros into the buffer. */
354 for (i
=0; i
<ZERO_BUF_SIZE
; i
++) {
358 /* Set up memory range for /dev/mem. */
359 m_geom
[MEM_DEV
].dv_size
= cvul64(mem_top
);
362 /*===========================================================================*
364 *===========================================================================*/
365 PRIVATE
int m_ioctl(dp
, m_ptr
, safe
)
366 struct driver
*dp
; /* pointer to driver structure */
367 message
*m_ptr
; /* pointer to control message */
370 /* I/O controls for the memory driver. Currently there is one I/O control:
371 * - MIOCRAMSIZE: to set the size of the RAM disk.
376 printf("m_transfer: unsafe?\n");
380 switch (m_ptr
->REQUEST
) {
382 /* Someone wants to create a new RAM disk with the given size. */
383 static int first_time
= 1;
386 phys_bytes ramdev_base
;
390 /* A ramdisk can be created only once, and only on RAM disk device. */
391 if (!first_time
) return(EPERM
);
392 if (m_ptr
->DEVICE
!= RAM_DEV
) return(EINVAL
);
393 if ((dv
= m_prepare(m_ptr
->DEVICE
)) == NIL_DEV
) return(ENXIO
);
396 ramdev_size
= m_ptr
->POSITION
;
398 /* Get request structure */
399 s
= sys_safecopyfrom(m_ptr
->IO_ENDPT
, (vir_bytes
)m_ptr
->IO_GRANT
,
400 0, (vir_bytes
)&ramdev_size
, sizeof(ramdev_size
), D
);
406 printf("allocating ramdisk of size 0x%x\n", ramdev_size
);
409 /* Try to allocate a piece of memory for the RAM disk. */
410 if (allocmem(ramdev_size
, &ramdev_base
) < 0) {
411 report("MEM", "warning, allocmem failed", errno
);
415 /* Store the values we got in the data store so we can retrieve
416 * them later on, in the unfortunate event of a crash.
418 if(ds_publish_u32(MY_DS_NAME_BASE
, ramdev_base
) != OK
||
419 ds_publish_u32(MY_DS_NAME_SIZE
, ramdev_size
) != OK
) {
420 panic("MEM","Couldn't store RAM disk details at DS.",s
);
424 printf("MEM stored size %u and base %u at DS, names %s and %s\n",
425 ramdev_size
, ramdev_base
, MY_DS_NAME_BASE
, MY_DS_NAME_SIZE
);
428 if (OK
!= (s
=sys_segctl(&m_seg
[RAM_DEV
], (u16_t
*) &s
,
429 (vir_bytes
*) &s
, ramdev_base
, ramdev_size
))) {
430 panic("MEM","Couldn't install remote segment.",s
);
433 dv
->dv_base
= cvul64(ramdev_base
);
434 dv
->dv_size
= cvul64(ramdev_size
);
441 struct mapreq mapreq
;
443 if ((*dp
->dr_prepare
)(m_ptr
->DEVICE
) == NIL_DEV
) return(ENXIO
);
444 if (m_device
!= MEM_DEV
)
447 do_map
= (m_ptr
->REQUEST
== MIOCMAP
); /* else unmap */
449 /* Get request structure */
450 r
= sys_safecopyfrom(m_ptr
->IO_ENDPT
, (vir_bytes
)m_ptr
->IO_GRANT
,
451 0, (vir_bytes
)&mapreq
, sizeof(mapreq
), D
);
455 r
= sys_vm_map(m_ptr
->IO_ENDPT
, do_map
,
456 (phys_bytes
)mapreq
.base
, mapreq
.size
, mapreq
.offset
);
461 return(do_diocntl(&m_dtab
, m_ptr
, safe
));
466 /*===========================================================================*
468 *===========================================================================*/
469 PRIVATE
void m_geometry(entry
)
470 struct partition
*entry
;
472 /* Memory devices don't have a geometry, but the outside world insists. */
473 entry
->cylinders
= div64u(m_geom
[m_device
].dv_size
, SECTOR_SIZE
) / (64 * 32);