atomicity fix when enabling paging

- before enabling paging VM asks kernel to resize its segments. This
  may cause kernel to segfault if APIC is used and an interrupt
  happens between this and paging enabled. As these are 2 separate
  vmctl calls it is not atomic. This patch fixes this problem. VM does
  not ask kernel to resize the segments in a separate call anymore.
  The new segments limit is part of the "enable paging" call. It
  generalizes this call in such a way that more information can be
  passed as need be or the information may be completely different if
  another architecture requires this.
This commit is contained in:
Tomas Hruby
2010-03-22 07:42:52 +00:00
parent a5094f7d7f
commit 12ef495cac
7 changed files with 55 additions and 23 deletions

View File

@@ -4,6 +4,8 @@
#include "../../proc.h"
#include "../../vm.h"
#include <machine/vm.h>
#include <minix/type.h>
#include <minix/syslib.h>
#include <minix/cpufeature.h>
@@ -956,8 +958,37 @@ PUBLIC int arch_phys_map_reply(int index, vir_bytes addr)
return OK;
}
PUBLIC int arch_enable_paging(void)
PUBLIC int arch_enable_paging(struct proc * caller, message * m_ptr)
{
struct vm_ep_data ep_data;
int r;
/*
* copy the extra data associated with the call from userspace
*/
if((r=data_copy(caller->p_endpoint, (vir_bytes)m_ptr->SVMCTL_VALUE,
KERNEL, (vir_bytes) &ep_data, sizeof(ep_data))) != OK) {
printf("vmctl_enable_paging: data_copy failed! (%d)\n", r);
return r;
}
/*
* when turning paging on i386 we also change the segment limits to make
* the special mappings requested by the kernel reachable
*/
if ((r = prot_set_kern_seg_limit(ep_data.data_seg_limit)) != OK)
return r;
/*
* install the new map provided by the call
*/
if (newmap(caller, caller, ep_data.mem_map) != OK)
panic("arch_enable_paging: newmap failed");
FIXLINMSG(caller);
assert(caller->p_delivermsg_lin == umap_local(caller, D,
caller->p_delivermsg_vir, sizeof(message)));
#ifdef CONFIG_APIC
/* if local APIC is enabled */
if (lapic_addr) {

View File

@@ -173,7 +173,7 @@ _PROTOTYPE( void arch_do_syscall, (struct proc *proc) );
_PROTOTYPE( int arch_phys_map, (int index, phys_bytes *addr,
phys_bytes *len, int *flags));
_PROTOTYPE( int arch_phys_map_reply, (int index, vir_bytes addr));
_PROTOTYPE( int arch_enable_paging, (void));
_PROTOTYPE( int arch_enable_paging, (struct proc * caller, message * m_ptr));
_PROTOTYPE( int copy_msg_from_user, (struct proc * p, message * user_mbuf,
message * dst));

View File

@@ -127,15 +127,7 @@ PUBLIC int do_vmctl(struct proc * caller, message * m_ptr)
vm_init(p);
if(!vm_running)
panic("do_vmctl: paging enabling failed");
if ((err = arch_enable_paging()) != OK) {
return err;
}
if(newmap(caller, p, (struct mem_map *) m_ptr->SVMCTL_VALUE) != OK)
panic("do_vmctl: newmap failed");
FIXLINMSG(p);
assert(p->p_delivermsg_lin ==
umap_local(p, D, p->p_delivermsg_vir, sizeof(message)));
return OK;
return arch_enable_paging(caller, m_ptr);
case VMCTL_KERN_PHYSMAP:
{
int i = m_ptr->SVMCTL_VALUE;