2 /* This file contains some utility routines for VM. */
6 #define _MINIX 1 /* To get the brk() prototype (as _brk()). */
8 #include <minix/callnr.h>
10 #include <minix/config.h>
11 #include <minix/const.h>
13 #include <minix/endpoint.h>
14 #include <minix/minlib.h>
15 #include <minix/type.h>
16 #include <minix/ipc.h>
17 #include <minix/sysutil.h>
18 #include <minix/syslib.h>
19 #include <minix/type.h>
20 #include <minix/bitmap.h>
27 #include <sys/param.h>
33 #include "sanitycheck.h"
35 #include <machine/archtypes.h>
36 #include "kernel/const.h"
37 #include "kernel/config.h"
38 #include "kernel/type.h"
39 #include "kernel/proc.h"
41 /*===========================================================================*
43 *===========================================================================*/
44 void get_mem_chunks(mem_chunks
)
45 struct memory
*mem_chunks
; /* store mem chunks here */
47 /* Initialize the free memory list from the 'memory' boot variable. Translate
48 * the byte offsets and sizes in this list to clicks, properly truncated.
50 phys_bytes base
, size
, limit
;
54 /* Obtain and parse memory from system environment. */
55 if(env_memory_parse(mem_chunks
, NR_MEMS
) != OK
)
56 panic("couldn't obtain memory chunks");
58 /* Round physical memory to clicks. Round start up, round end down. */
59 for (i
= 0; i
< NR_MEMS
; i
++) {
60 memp
= &mem_chunks
[i
]; /* next mem chunk is stored here */
61 base
= mem_chunks
[i
].base
;
62 size
= mem_chunks
[i
].size
;
64 base
= (phys_bytes
) (CLICK_CEIL(base
));
65 limit
= (phys_bytes
) (CLICK_FLOOR(limit
));
67 memp
->base
= memp
->size
= 0;
69 memp
->base
= base
>> CLICK_SHIFT
;
70 memp
->size
= (limit
- base
) >> CLICK_SHIFT
;
76 /*===========================================================================*
78 *===========================================================================*/
79 void reserve_proc_mem(mem_chunks
, map_ptr
)
80 struct memory
*mem_chunks
; /* store mem chunks here */
81 struct mem_map
*map_ptr
; /* memory to remove */
83 /* Remove server memory from the free memory list.
86 for (memp
= mem_chunks
; memp
< &mem_chunks
[NR_MEMS
]; memp
++) {
87 if(memp
->base
<= map_ptr
[T
].mem_phys
88 && memp
->base
+memp
->size
>= map_ptr
[T
].mem_phys
)
90 phys_bytes progsz
= map_ptr
[S
].mem_phys
91 - map_ptr
[T
].mem_phys
;
92 phys_bytes progend
= map_ptr
[S
].mem_phys
;
94 if (memp
->base
== map_ptr
[T
].mem_phys
) {
100 /* have to split mem_chunks */
101 if(mem_chunks
[NR_MEMS
-1].size
>0)
102 panic("reserve_proc_mem: can't find free mem_chunks to map: 0x%lx",
103 map_ptr
[T
].mem_phys
);
104 for(mempr
=&mem_chunks
[NR_MEMS
-1];mempr
>memp
;mempr
--) {
107 assert(memp
< &mem_chunks
[NR_MEMS
-1]);
109 (memp
+1)->base
= progend
;
110 (memp
+1)->size
= memp
->base
+ memp
->size
112 memp
->size
= map_ptr
[T
].mem_phys
- memp
->base
;
117 if (memp
>= &mem_chunks
[NR_MEMS
]) {
118 panic("reserve_proc_mem: can't find map in mem_chunks: 0x%lx",
119 map_ptr
[T
].mem_phys
);
124 /*===========================================================================*
126 *===========================================================================*/
127 int vm_isokendpt(endpoint_t endpoint
, int *proc
)
129 *proc
= _ENDPOINT_P(endpoint
);
130 if(*proc
< 0 || *proc
>= NR_PROCS
)
132 if(*proc
>= 0 && endpoint
!= vmproc
[*proc
].vm_endpoint
)
134 if(*proc
>= 0 && !(vmproc
[*proc
].vm_flags
& VMF_INUSE
))
140 /*===========================================================================*
142 *===========================================================================*/
143 int do_info(message
*m
)
145 struct vm_stats_info vsi
;
146 struct vm_usage_info vui
;
147 static struct vm_region_info vri
[MAX_VRI_COUNT
];
149 vir_bytes addr
, size
, next
, ptr
;
150 int r
, pr
, dummy
, count
, free_pages
, largest_contig
;
152 if (vm_isokendpt(m
->m_source
, &pr
) != OK
)
156 ptr
= (vir_bytes
) m
->VMI_PTR
;
158 switch(m
->VMI_WHAT
) {
160 vsi
.vsi_pagesize
= VM_PAGE_SIZE
;
161 vsi
.vsi_total
= total_pages
;
162 memstats(&dummy
, &free_pages
, &largest_contig
);
163 vsi
.vsi_free
= free_pages
;
164 vsi
.vsi_largest
= largest_contig
;
166 get_stats_info(&vsi
);
168 addr
= (vir_bytes
) &vsi
;
174 if (vm_isokendpt(m
->VMI_EP
, &pr
) != OK
)
177 get_usage_info(&vmproc
[pr
], &vui
);
179 addr
= (vir_bytes
) &vui
;
185 if (vm_isokendpt(m
->VMI_EP
, &pr
) != OK
)
188 count
= MIN(m
->VMI_COUNT
, MAX_VRI_COUNT
);
191 count
= get_region_info(&vmproc
[pr
], vri
, count
, &next
);
193 m
->VMI_COUNT
= count
;
196 addr
= (vir_bytes
) vri
;
197 size
= sizeof(vri
[0]) * count
;
208 /* Make sure that no page faults can occur while copying out. A page
209 * fault would cause the kernel to send a notify to us, while we would
210 * be waiting for the result of the copy system call, resulting in a
211 * deadlock. Note that no memory mapping can be undone without the
212 * involvement of VM, so we are safe until we're done.
214 r
= handle_memory(vmp
, ptr
, size
, 1 /*wrflag*/);
215 if (r
!= OK
) return r
;
217 /* Now that we know the copy out will succeed, perform the actual copy
220 return sys_datacopy(SELF
, addr
,
221 (vir_bytes
) vmp
->vm_endpoint
, ptr
, size
);
224 /*===========================================================================*
226 *===========================================================================*/
227 int swap_proc_slot(struct vmproc
*src_vmp
, struct vmproc
*dst_vmp
)
229 struct vmproc orig_src_vmproc
, orig_dst_vmproc
;
232 printf("VM: swap_proc: swapping %d (%d) and %d (%d)\n",
233 src_vmp
->vm_endpoint
, src_vmp
->vm_slot
,
234 dst_vmp
->vm_endpoint
, dst_vmp
->vm_slot
);
237 /* Save existing data. */
238 orig_src_vmproc
= *src_vmp
;
239 orig_dst_vmproc
= *dst_vmp
;
242 *src_vmp
= orig_dst_vmproc
;
243 *dst_vmp
= orig_src_vmproc
;
245 /* Preserve endpoints and slot numbers. */
246 src_vmp
->vm_endpoint
= orig_src_vmproc
.vm_endpoint
;
247 src_vmp
->vm_slot
= orig_src_vmproc
.vm_slot
;
248 dst_vmp
->vm_endpoint
= orig_dst_vmproc
.vm_endpoint
;
249 dst_vmp
->vm_slot
= orig_dst_vmproc
.vm_slot
;
252 printf("VM: swap_proc: swapped %d (%d) and %d (%d)\n",
253 src_vmp
->vm_endpoint
, src_vmp
->vm_slot
,
254 dst_vmp
->vm_endpoint
, dst_vmp
->vm_slot
);
260 /*===========================================================================*
261 * swap_proc_dyn_data *
262 *===========================================================================*/
263 int swap_proc_dyn_data(struct vmproc
*src_vmp
, struct vmproc
*dst_vmp
)
268 is_vm
= (dst_vmp
->vm_endpoint
== VM_PROC_NR
);
270 /* For VM, transfer memory regions above the stack first. */
273 printf("VM: swap_proc_dyn_data: tranferring regions above the stack from old VM (%d) to new VM (%d)\n",
274 src_vmp
->vm_endpoint
, dst_vmp
->vm_endpoint
);
276 r
= pt_map_in_range(src_vmp
, dst_vmp
, VM_STACKTOP
, 0);
278 printf("swap_proc_dyn_data: pt_map_in_range failed\n");
284 printf("VM: swap_proc_dyn_data: swapping regions' parents for %d (%d) and %d (%d)\n",
285 src_vmp
->vm_endpoint
, src_vmp
->vm_slot
,
286 dst_vmp
->vm_endpoint
, dst_vmp
->vm_slot
);
289 /* Swap vir_regions' parents. */
290 map_setparent(src_vmp
);
291 map_setparent(dst_vmp
);
293 /* For regular processes, transfer regions above the stack now.
294 * In case of rollback, we need to skip this step. To sandbox the
295 * new instance and prevent state corruption on rollback, we share all
296 * the regions between the two instances as COW.
299 struct vir_region
*vr
;
300 vr
= map_lookup(dst_vmp
, VM_STACKTOP
);
301 if(vr
&& !map_lookup(src_vmp
, VM_STACKTOP
)) {
303 printf("VM: swap_proc_dyn_data: tranferring regions above the stack from %d to %d\n",
304 src_vmp
->vm_endpoint
, dst_vmp
->vm_endpoint
);
306 r
= map_proc_copy_from(src_vmp
, dst_vmp
, vr
);