tty: try more often to get the config byte.
[minix.git] / servers / vm / utility.c
blob2ca3e13c599f38550ebde577d53fef1b103963fd
2 /* This file contains some utility routines for VM. */
4 #define _SYSTEM 1
6 #define _MINIX 1 /* To get the brk() prototype (as _brk()). */
7 #define brk _brk /* Our brk() must redefine _brk(). */
9 #include <minix/callnr.h>
10 #include <minix/com.h>
11 #include <minix/config.h>
12 #include <minix/const.h>
13 #include <minix/ds.h>
14 #include <minix/endpoint.h>
15 #include <minix/minlib.h>
16 #include <minix/type.h>
17 #include <minix/ipc.h>
18 #include <minix/sysutil.h>
19 #include <minix/syslib.h>
20 #include <minix/type.h>
21 #include <minix/bitmap.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <env.h>
25 #include <unistd.h>
26 #include <memory.h>
27 #include <assert.h>
29 #include "proto.h"
30 #include "glo.h"
31 #include "util.h"
32 #include "region.h"
34 #include <machine/archtypes.h>
35 #include "kernel/const.h"
36 #include "kernel/config.h"
37 #include "kernel/type.h"
38 #include "kernel/proc.h"
40 #define SWAP_PROC_DEBUG 0
42 /*===========================================================================*
43 * get_mem_map *
44 *===========================================================================*/
45 PUBLIC int get_mem_map(proc_nr, mem_map)
46 int proc_nr; /* process to get map of */
47 struct mem_map *mem_map; /* put memory map here */
49 struct proc p;
50 int s;
52 if ((s=sys_getproc(&p, proc_nr)) != OK)
53 return(s);
55 memcpy(mem_map, p.p_memmap, sizeof(p.p_memmap));
56 return(OK);
59 /*===========================================================================*
60 * get_mem_chunks *
61 *===========================================================================*/
62 PUBLIC void get_mem_chunks(mem_chunks)
63 struct memory *mem_chunks; /* store mem chunks here */
65 /* Initialize the free memory list from the 'memory' boot variable. Translate
66 * the byte offsets and sizes in this list to clicks, properly truncated.
68 phys_bytes base, size, limit;
69 int i;
70 struct memory *memp;
72 /* Obtain and parse memory from system environment. */
73 if(env_memory_parse(mem_chunks, NR_MEMS) != OK)
74 panic("couldn't obtain memory chunks");
76 /* Round physical memory to clicks. Round start up, round end down. */
77 for (i = 0; i < NR_MEMS; i++) {
78 memp = &mem_chunks[i]; /* next mem chunk is stored here */
79 base = mem_chunks[i].base;
80 size = mem_chunks[i].size;
81 limit = base + size;
82 base = (phys_bytes) (CLICK_CEIL(base));
83 limit = (phys_bytes) (CLICK_FLOOR(limit));
84 if (limit <= base) {
85 memp->base = memp->size = 0;
86 } else {
87 memp->base = base >> CLICK_SHIFT;
88 memp->size = (limit - base) >> CLICK_SHIFT;
93 /*===========================================================================*
94 * reserve_proc_mem *
95 *===========================================================================*/
96 PUBLIC void reserve_proc_mem(mem_chunks, map_ptr)
97 struct memory *mem_chunks; /* store mem chunks here */
98 struct mem_map *map_ptr; /* memory to remove */
100 /* Remove server memory from the free memory list. The boot monitor
101 * promises to put processes at the start of memory chunks. The
102 * tasks all use same base address, so only the first task changes
103 * the memory lists. The servers and init have their own memory
104 * spaces and their memory will be removed from the list.
106 struct memory *memp;
107 for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) {
108 if (memp->base == map_ptr[T].mem_phys) {
109 memp->base += map_ptr[T].mem_len + map_ptr[S].mem_vir;
110 memp->size -= map_ptr[T].mem_len + map_ptr[S].mem_vir;
111 break;
114 if (memp >= &mem_chunks[NR_MEMS])
116 panic("reserve_proc_mem: can't find map in mem_chunks: 0x%lx",
117 map_ptr[T].mem_phys);
121 /*===========================================================================*
122 * vm_isokendpt *
123 *===========================================================================*/
124 PUBLIC int vm_isokendpt(endpoint_t endpoint, int *proc)
126 *proc = _ENDPOINT_P(endpoint);
127 if(*proc < 0 || *proc >= NR_PROCS)
128 return EINVAL;
129 if(*proc >= 0 && endpoint != vmproc[*proc].vm_endpoint)
130 return EDEADSRCDST;
131 if(*proc >= 0 && !(vmproc[*proc].vm_flags & VMF_INUSE))
132 return EDEADSRCDST;
133 return OK;
137 struct proc mytmpproc;
139 /*===========================================================================*
140 * get_stack_ptr *
141 *===========================================================================*/
142 PUBLIC int get_stack_ptr(proc_nr_e, sp)
143 int proc_nr_e; /* process to get sp of */
144 vir_bytes *sp; /* put stack pointer here */
146 int s;
148 if ((s=sys_getproc(&mytmpproc, proc_nr_e)) != OK)
149 return(s);
150 *sp = mytmpproc.p_reg.sp;
151 return(OK);
154 /*===========================================================================*
155 * _brk *
156 *===========================================================================*/
157 extern char *_brksize;
158 PUBLIC int brk(brk_addr)
159 char *brk_addr;
161 int r;
162 struct vmproc *vmm = &vmproc[VM_PROC_NR];
164 /* VM wants to call brk() itself. */
165 if((r=real_brk(vmm, (vir_bytes) brk_addr)) != OK)
166 panic("VM: brk() on myself failed");
167 _brksize = brk_addr;
168 return 0;
171 /*===========================================================================*
172 * do_info *
173 *===========================================================================*/
174 PUBLIC int do_info(message *m)
176 struct vm_stats_info vsi;
177 struct vm_usage_info vui;
178 static struct vm_region_info vri[MAX_VRI_COUNT];
179 struct vmproc *vmp;
180 vir_bytes addr, size, next, ptr;
181 int r, pr, dummy, count;
183 if (vm_isokendpt(m->m_source, &pr) != OK)
184 return EINVAL;
185 vmp = &vmproc[pr];
187 ptr = (vir_bytes) m->VMI_PTR;
189 switch(m->VMI_WHAT) {
190 case VMIW_STATS:
191 vsi.vsi_pagesize = VM_PAGE_SIZE;
192 vsi.vsi_total = total_pages;
193 memstats(&dummy, &vsi.vsi_free, &vsi.vsi_largest);
195 addr = (vir_bytes) &vsi;
196 size = sizeof(vsi);
198 break;
200 case VMIW_USAGE:
201 if (vm_isokendpt(m->VMI_EP, &pr) != OK)
202 return EINVAL;
204 get_usage_info(&vmproc[pr], &vui);
206 addr = (vir_bytes) &vui;
207 size = sizeof(vui);
209 break;
211 case VMIW_REGION:
212 if (vm_isokendpt(m->VMI_EP, &pr) != OK)
213 return EINVAL;
215 count = MIN(m->VMI_COUNT, MAX_VRI_COUNT);
216 next = m->VMI_NEXT;
218 count = get_region_info(&vmproc[pr], vri, count, &next);
220 m->VMI_COUNT = count;
221 m->VMI_NEXT = next;
223 addr = (vir_bytes) vri;
224 size = sizeof(vri[0]) * count;
226 break;
228 default:
229 return EINVAL;
232 if (size == 0)
233 return OK;
235 /* Make sure that no page faults can occur while copying out. A page
236 * fault would cause the kernel to send a notify to us, while we would
237 * be waiting for the result of the copy system call, resulting in a
238 * deadlock. Note that no memory mapping can be undone without the
239 * involvement of VM, so we are safe until we're done.
241 r = handle_memory(vmp, arch_vir2map(vmp, ptr), size, 1 /*wrflag*/);
242 if (r != OK) return r;
244 /* Now that we know the copy out will succeed, perform the actual copy
245 * operation.
247 return sys_datacopy(SELF, addr,
248 (vir_bytes) vmp->vm_endpoint, ptr, size);
251 /*===========================================================================*
252 * swap_proc *
253 *===========================================================================*/
254 PUBLIC int swap_proc(endpoint_t src_e, endpoint_t dst_e)
256 struct vmproc *src_vmp, *dst_vmp;
257 struct vmproc orig_src_vmproc, orig_dst_vmproc;
258 int src_p, dst_p, r;
259 struct vir_region *vr;
261 /* Lookup slots for source and destination process. */
262 if(vm_isokendpt(src_e, &src_p) != OK) {
263 printf("swap_proc: bad src endpoint %d\n", src_e);
264 return EINVAL;
266 src_vmp = &vmproc[src_p];
267 if(vm_isokendpt(dst_e, &dst_p) != OK) {
268 printf("swap_proc: bad dst endpoint %d\n", dst_e);
269 return EINVAL;
271 dst_vmp = &vmproc[dst_p];
273 #if SWAP_PROC_DEBUG
274 printf("swap_proc: swapping %d (%d, %d) and %d (%d, %d)\n",
275 src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
276 dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
278 printf("swap_proc: map_printmap for source before swapping:\n");
279 map_printmap(src_vmp);
280 printf("swap_proc: map_printmap for destination before swapping:\n");
281 map_printmap(dst_vmp);
282 #endif
284 /* Save existing data. */
285 orig_src_vmproc = *src_vmp;
286 orig_dst_vmproc = *dst_vmp;
288 /* Swap slots. */
289 *src_vmp = orig_dst_vmproc;
290 *dst_vmp = orig_src_vmproc;
292 /* Preserve endpoints and slot numbers. */
293 src_vmp->vm_endpoint = orig_src_vmproc.vm_endpoint;
294 src_vmp->vm_slot = orig_src_vmproc.vm_slot;
295 dst_vmp->vm_endpoint = orig_dst_vmproc.vm_endpoint;
296 dst_vmp->vm_slot = orig_dst_vmproc.vm_slot;
298 /* Preserve vir_region's parents. */
299 for(vr = src_vmp->vm_regions; vr; vr = vr->next) {
300 vr->parent = src_vmp;
302 for(vr = dst_vmp->vm_regions; vr; vr = vr->next) {
303 vr->parent = dst_vmp;
306 /* Adjust page tables. */
307 assert(src_vmp->vm_flags & VMF_HASPT);
308 assert(dst_vmp->vm_flags & VMF_HASPT);
309 pt_bind(&src_vmp->vm_pt, src_vmp);
310 pt_bind(&dst_vmp->vm_pt, dst_vmp);
311 if((r=sys_vmctl(SELF, VMCTL_FLUSHTLB, 0)) != OK) {
312 panic("swap_proc: VMCTL_FLUSHTLB failed: %d", r);
315 #if SWAP_PROC_DEBUG
316 printf("swap_proc: swapped %d (%d, %d) and %d (%d, %d)\n",
317 src_vmp->vm_endpoint, src_p, src_vmp->vm_slot,
318 dst_vmp->vm_endpoint, dst_p, dst_vmp->vm_slot);
320 printf("swap_proc: map_printmap for source after swapping:\n");
321 map_printmap(src_vmp);
322 printf("swap_proc: map_printmap for destination after swapping:\n");
323 map_printmap(dst_vmp);
324 #endif
326 return OK;