From ad9ba944d10d6c068a1af6aecd1f0afea875ae1c Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Tue, 9 Feb 2010 15:13:52 +0000 Subject: [PATCH] Early address space switch - switch_address_space() implements a switch of the user address space for the destination process - this makes memory of this process easily accessible, e.g. a pointer valid in the userspace can be used with a little complexity to access the process's memory - the switch does not happed only just before we return to userspace, however, it happens right after we know which process we are going to schedule. This happens before we start processing the misc flags of this process so its memory is available - if the process becomes not runnable while processing the mics flags we pick a new process and we switch the address space again which introduces possibly a little bit more overhead, however, it is hopefully hidden by reducing the overheads when we actually access the memory --- kernel/arch/i386/klib386.S | 36 ++++++++++++++++++++++++++++++++++++ kernel/arch/i386/mpx386.S | 17 ----------------- kernel/arch/i386/system.c | 3 --- kernel/proc.c | 2 ++ kernel/proto.h | 1 + 5 files changed, 39 insertions(+), 20 deletions(-) diff --git a/kernel/arch/i386/klib386.S b/kernel/arch/i386/klib386.S index 6e136cc11..852fa6c8b 100644 --- a/kernel/arch/i386/klib386.S +++ b/kernel/arch/i386/klib386.S @@ -692,3 +692,39 @@ idt_reload: reload_ds: RELOAD_SEG_REG(%ds) ret + +/*===========================================================================*/ +/* switch_address_space */ +/*===========================================================================*/ +/* PUBLIC void switch_address_space(struct proc *p) + * + * sets the %cr3 register to the supplied value if it is not already set to the + * same value in which case it would only result in an extra TLB flush which is + * not desirable + */ + .balign 16 +.globl switch_address_space +switch_address_space: + + /* read the process pointer */ + mov 4(%esp), %edx + /* enable process' segment descriptors */ + lldt P_LDT_SEL(%edx) + /* get the new cr3 value */ + movl P_CR3(%edx), %eax + /* test if the new cr3 != NULL */ + cmpl $0, %eax + je 0f + + /* + * test if the cr3 is loaded with the current value to avoid unnecessary + * TLB flushes + */ + mov %cr3, %ecx + cmp %ecx, %eax + je 0f + mov %eax, %cr3 + mov %edx, ptproc + movl $0, dirtypde +0: + ret diff --git a/kernel/arch/i386/mpx386.S b/kernel/arch/i386/mpx386.S index d67ba0acc..321bc59a5 100644 --- a/kernel/arch/i386/mpx386.S +++ b/kernel/arch/i386/mpx386.S @@ -470,22 +470,6 @@ restart: /* %eax is set by schedcheck() to the process to run */ mov %eax, %ebp /* will assume P_STACKBASE == 0 */ - cmpl $0, P_CR3(%ebp) - jz 0f - - /* - * test if the cr3 is loaded with the current value to avoid unnecessary - * TLB flushes - */ - mov P_CR3(%ebp), %eax - mov %cr3, %ecx - cmp %ecx, %eax - jz 0f - mov %eax, %cr3 - mov %ebp, ptproc - movl $0, dirtypde -0: - /* reconstruct the stack for iret */ movl SSREG(%ebp), %eax push %eax @@ -500,7 +484,6 @@ restart: RESTORE_GP_REGS(%ebp) - lldt P_LDT_SEL(%ebp) /* enable process' segment descriptors */ RESTORE_SEGS(%ebp) movl %ss:BPREG(%ebp), %ebp diff --git a/kernel/arch/i386/system.c b/kernel/arch/i386/system.c index 703056cc3..d857eeece 100644 --- a/kernel/arch/i386/system.c +++ b/kernel/arch/i386/system.c @@ -477,9 +477,6 @@ PUBLIC void arch_do_syscall(struct proc *proc) m_ptr = (message *) proc->p_reg.bx; bit_map = proc->p_reg.dx; - /* do_ipc() expects the given process's memory to be accessible. */ - vm_set_cr3(proc); - /* Make the system call, for real this time. */ proc->p_reg.retreg = do_ipc(call_nr, src_dst_e, m_ptr, bit_map); } diff --git a/kernel/proc.c b/kernel/proc.c index 99a2b202d..04062a105 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -198,6 +198,8 @@ not_runnable_pick_new: idle(); } + switch_address_space(proc_ptr); + check_misc_flags: vmassert(proc_ptr); diff --git a/kernel/proto.h b/kernel/proto.h index 69c4d9f07..5226727a4 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -171,4 +171,5 @@ _PROTOTYPE( int arch_phys_map, (int index, phys_bytes *addr, _PROTOTYPE( int arch_phys_map_reply, (int index, vir_bytes addr)); _PROTOTYPE( int arch_enable_paging, (void)); +_PROTOTYPE(void switch_address_space, (struct proc * p)); #endif /* PROTO_H */