1 /* This file contains the device dependent part of the drivers for the
2 * following special files:
3 * /dev/null - null device (data sink)
4 * /dev/mem - absolute memory
5 * /dev/kmem - kernel virtual memory
6 * /dev/ram - RAM disk
7 *
8 * The file contains one entry point:
9 *
10 * mem_task: main entry when system is brought up
11 *
12 * Changes:
13 * 20 Apr 1992 by Kees J. Bot: device dependent/independent split
14 */
15
16 #include "kernel.h"
17 #include "driver.h"
18 #include <sys/ioctl.h>
19
20 #define NR_RAMS 4 /* number of RAM-type devices */
21
22 PRIVATE struct device m_geom[NR_RAMS]; /* Base and size of each RAM disk */
23 PRIVATE int m_device; /* current device */
24
25 FORWARD _PROTOTYPE( struct device *m_prepare, (int device) );
26 FORWARD _PROTOTYPE( int m_schedule, (int proc_nr, struct iorequest_s *iop) );
27 FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr) );
28 FORWARD _PROTOTYPE( void m_init, (void) );
29 FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr) );
30 FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry) );
31
32
33 /* Entry points to this driver. */
34 PRIVATE struct driver m_dtab = {
35 no_name, /* current device's name */
36 m_do_open, /* open or mount */
37 do_nop, /* nothing on a close */
38 m_ioctl, /* specify ram disk geometry */
39 m_prepare, /* prepare for I/O on a given minor device */
40 m_schedule, /* do the I/O */
41 nop_finish, /* schedule does the work, no need to be smart */
42 nop_cleanup, /* nothing's dirty */
43 m_geometry, /* memory device "geometry" */
44 };
45
46
47 /*===========================================================================*
48 * mem_task *
49 *===========================================================================*/
50 PUBLIC void mem_task()
51 {
52 m_init();
53 driver_task(&m_dtab);
54 }
55
56
57 /*===========================================================================*
58 * m_prepare *
59 *===========================================================================*/
60 PRIVATE struct device *m_prepare(device)
61 int device;
62 {
63 /* Prepare for I/O on a device. */
64
65 if (device < 0 || device >= NR_RAMS) return(NIL_DEV);
66 m_device = device;
67
68 return(&m_geom[device]);
69 }
70
71
72 /*===========================================================================*
73 * m_schedule *
74 *===========================================================================*/
75 PRIVATE int m_schedule(proc_nr, iop)
76 int proc_nr; /* process doing the request */
77 struct iorequest_s *iop; /* pointer to read or write request */
78 {
79 /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
80
81 int device, count, opcode;
82 phys_bytes mem_phys, user_phys;
83 struct device *dv;
84
85 /* Type of request */
86 opcode = iop->io_request & ~OPTIONAL_IO;
87
88 /* Get minor device number and check for /dev/null. */
89 device = m_device;
90 dv = &m_geom[device];
91
92 /* Determine address where data is to go or to come from. */
93 user_phys = numap(proc_nr, (vir_bytes) iop->io_buf,
94 (vir_bytes) iop->io_nbytes);
95 if (user_phys == 0) return(iop->io_nbytes = EINVAL);
96
97 if (device == NULL_DEV) {
98 /* /dev/null: Black hole. */
99 if (opcode == DEV_WRITE) iop->io_nbytes = 0;
100 count = 0;
101 } else {
102 /* /dev/mem, /dev/kmem, or /dev/ram: Check for EOF */
103 if (iop->io_position >= dv->dv_size) return(OK);
104 count = iop->io_nbytes;
105 if (iop->io_position + count > dv->dv_size)
106 count = dv->dv_size - iop->io_position;
107 }
108
109 /* Set up 'mem_phys' for /dev/mem, /dev/kmem, or /dev/ram */
110 mem_phys = dv->dv_base + iop->io_position;
111
112 /* Book the number of bytes to be transferred in advance. */
113 iop->io_nbytes -= count;
114
115 if (count == 0) return(OK);
116
117 /* Copy the data. */
118 if (opcode == DEV_READ)
119 phys_copy(mem_phys, user_phys, (phys_bytes) count);
120 else
121 phys_copy(user_phys, mem_phys, (phys_bytes) count);
122
123 return(OK);
124 }
125
126
127 /*============================================================================*
128 * m_do_open *
129 *============================================================================*/
130 PRIVATE int m_do_open(dp, m_ptr)
131 struct driver *dp;
132 message *m_ptr;
133 {
134 /* Check device number on open. Give I/O privileges to a process opening
135 * /dev/mem or /dev/kmem.
136 */
137
138 if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
139
140 #if (CHIP == INTEL)
141 if (m_device == MEM_DEV || m_device == KMEM_DEV)
142 enable_iop(proc_addr(m_ptr->PROC_NR));
143 #endif
144
145 return(OK);
146 }
147
148
149 /*===========================================================================*
150 * m_init *
151 *===========================================================================*/
152 PRIVATE void m_init()
153 {
154 #if (MACHINE != SUN)
155 /* Initialize this task. */
156 extern int _end;
157
158 m_geom[KMEM_DEV].dv_base = vir2phys(0);
159 m_geom[KMEM_DEV].dv_size = vir2phys(&_end);
160 #else
161 /*
162 * In smx, the kernel memory is regarded as beginning at 0 and
163 * extending to the end of the kernel data segment, even though
164 * a large area (from 0 to the start of the kernel text segment) lies
165 * outside the kernrel. This way of doing this does have the advantage,
166 * however, that addresses of kernel variables can be used directly
167 * as offsets into /dev/kmem when extracting data from the kernel.
168 * A similar approach is used for /dev/mem.
169 */
170 struct proc *rp = BEG_PROC_ADDR;
171
172 m_geom[KMEM_DEV].dv_base = 0;
173 m_geom[KMEM_DEV].dv_size = code_base + (rp->p_map[T].mem_len << CLICK_SHIFT)
174 + (rp->p_map[D].mem_len << CLICK_SHIFT);
175 #endif
176
177 #if (CHIP == INTEL)
178 if (!protected_mode) {
179 m_geom[MEM_DEV].dv_size = 0x100000; /* 1M for 8086 systems */
180 } else {
181 #if _WORD_SIZE == 2
182 m_geom[MEM_DEV].dv_size = 0x1000000; /* 16M for 286 systems */
183 #else
184 m_geom[MEM_DEV].dv_size = 0xFFFFFFFF; /* 4G-1 for 386 systems */
185 #endif
186 }
187 #else /* !(CHIP == INTEL) */
188 # if (MACHINE == SUN)
189 m_geom[MEM_DEV].dv_base = 0; /* See KMEM_DEV comment */
190 m_geom[MEM_DEV].dv_size = code_base + (tot_mem_size << CLICK_SHIFT);
191 # else
192 # if (CHIP == M68000)
193 m_geom[MEM_DEV].dv_size = MEM_BYTES;
194 # else /* !(CHIP == M68000) */
195 # error /* memory limit not set up */
196 # endif /* !(CHIP == M68000) */
197 # endif
198 #endif /* !(CHIP == INTEL) */
199 }
200
201
202 /*===========================================================================*
203 * m_ioctl *
204 *===========================================================================*/
205 PRIVATE int m_ioctl(dp, m_ptr)
206 struct driver *dp;
207 message *m_ptr; /* pointer to read or write message */
208 {
209 /* Set parameters for one of the RAM disks. */
210
211 unsigned long bytesize;
212 unsigned base, size;
213 struct memory *memp;
214 static struct psinfo psinfo = { NR_TASKS, NR_PROCS, (vir_bytes) proc, 0, 0 };
215 phys_bytes psinfo_phys;
216
217 switch (m_ptr->REQUEST) {
218 case MIOCRAMSIZE:
219 /* FS sets the RAM disk size. */
220 if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
221
222 bytesize = m_ptr->POSITION * BLOCK_SIZE;
223 size = (bytesize + CLICK_SHIFT-1) >> CLICK_SHIFT;
224
225 /* Find a memory chunk big enough for the RAM disk. */
226 memp= &mem[NR_MEMS];
227 while ((--memp)->size < size) {
228 if (memp == mem) panic("RAM disk is too big", NO_NUM);
229 }
230 base = memp->base;
231 memp->base += size;
232 memp->size -= size;
233
234 m_geom[RAM_DEV].dv_base = (unsigned long) base << CLICK_SHIFT;
235 m_geom[RAM_DEV].dv_size = bytesize;
236 break;
237 case MIOCSPSINFO:
238 /* MM or FS set the address of their process table. */
239 if (m_ptr->PROC_NR == MM_PROC_NR) {
240 #if (MACHINE == SUN)
241 /*
242 * Store physical address for Suns---see comment on
243 * initialising m_geom[KMEM_DEV] and [MEM_DEV]as to why.
244 */
245 psinfo.mproc = numap(m_ptr->PROC_NR,
246 (vir_bytes) m_ptr->ADDRESS, 1);
247 #else
248 psinfo.mproc = (vir_bytes) m_ptr->ADDRESS;
249 #endif
250 } else
251 if (m_ptr->PROC_NR == FS_PROC_NR) {
252 #if (MACHINE == SUN)
253 psinfo.fproc = numap(m_ptr->PROC_NR,
254 (vir_bytes) m_ptr->ADDRESS, 1);
255 #else
256 psinfo.fproc = (vir_bytes) m_ptr->ADDRESS;
257 #endif
258 } else {
259 return(EPERM);
260 }
261 break;
262 case MIOCGPSINFO:
263 /* The ps program wants the process table addresses. */
264 psinfo_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
265 sizeof(psinfo));
266 if (psinfo_phys == 0) return(EFAULT);
267 phys_copy(vir2phys(&psinfo), psinfo_phys, (phys_bytes) sizeof(psinfo));
268 break;
269 default:
270 return(do_diocntl(&m_dtab, m_ptr));
271 }
272 return(OK);
273 }
274
275
276 /*============================================================================*
277 * m_geometry *
278 *============================================================================*/
279 PRIVATE void m_geometry(entry)
280 struct partition *entry;
281 {
282 /* Memory devices don't have a geometry, but the outside world insists. */
283 entry->cylinders = (m_geom[m_device].dv_size >> SECTOR_SHIFT) / (64 * 32);
284 entry->heads = 64;
285 entry->sectors = 32;
286 }
287
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.