From owner-dev-commits-src-all@freebsd.org Thu Mar 18 19:16:21 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 409CF5A9B14; Thu, 18 Mar 2021 19:16:21 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4F1cFd1Nftz4cvv; Thu, 18 Mar 2021 19:16:21 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 22A2A2713A; Thu, 18 Mar 2021 19:16:21 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 12IJGLPH096928; Thu, 18 Mar 2021 19:16:21 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 12IJGLVd096927; Thu, 18 Mar 2021 19:16:21 GMT (envelope-from git) Date: Thu, 18 Mar 2021 19:16:21 GMT Message-Id: <202103181916.12IJGLVd096927@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: John Baldwin Subject: git: a7883464fcc4 - main - x86: Reduce code duplication in cpu_fork() and cpu_copy_thread(). MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: jhb X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a7883464fcc45b78e6aa01222682ae40f787a378 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 18 Mar 2021 19:16:21 -0000 The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=a7883464fcc45b78e6aa01222682ae40f787a378 commit a7883464fcc45b78e6aa01222682ae40f787a378 Author: John Baldwin AuthorDate: 2021-03-18 19:13:17 +0000 Commit: John Baldwin CommitDate: 2021-03-18 19:13:17 +0000 x86: Reduce code duplication in cpu_fork() and cpu_copy_thread(). Add copy_thread() to hold shared code. Reviewed by: kib MFC after: 1 week Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D29228 --- sys/amd64/amd64/vm_machdep.c | 167 +++++++++++++++------------------------ sys/i386/i386/vm_machdep.c | 184 +++++++++++++++++-------------------------- 2 files changed, 137 insertions(+), 214 deletions(-) diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index a17ddd4ba6d8..0527ef95cf3b 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -136,6 +136,65 @@ alloc_fpusave(int flags) return (res); } +/* + * Common code shared between cpu_fork() and cpu_copy_thread() for + * initializing a thread. + */ +static void +copy_thread(struct thread *td1, struct thread *td2) +{ + struct pcb *pcb2; + + pcb2 = td2->td_pcb; + + /* Ensure that td1's pcb is up to date for user threads. */ + if ((td2->td_pflags & TDP_KTHREAD) == 0) { + MPASS(td1 == curthread); + fpuexit(td1); + update_pcb_bases(td1->td_pcb); + } + + /* Copy td1's pcb */ + bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); + + /* Properly initialize pcb_save */ + pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); + + /* Kernel threads start with clean FPU and segment bases. */ + if ((td2->td_pflags & TDP_KTHREAD) != 0) { + pcb2->pcb_fsbase = 0; + pcb2->pcb_gsbase = 0; + clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE | + PCB_KERNFPU | PCB_KERNFPU_THR); + } else { + MPASS((pcb2->pcb_flags & (PCB_KERNFPU | PCB_KERNFPU_THR)) == 0); + bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), + cpu_max_ext_state_size); + } + + /* + * Set registers for trampoline to user mode. Leave space for the + * return address on stack. These are the kernel mode register values. + */ + pcb2->pcb_r12 = (register_t)fork_return; /* fork_trampoline argument */ + pcb2->pcb_rbp = 0; + pcb2->pcb_rsp = (register_t)td2->td_frame - sizeof(void *); + pcb2->pcb_rbx = (register_t)td2; /* fork_trampoline argument */ + pcb2->pcb_rip = (register_t)fork_trampoline; + /*- + * pcb2->pcb_dr*: cloned above. + * pcb2->pcb_savefpu: cloned above. + * pcb2->pcb_flags: cloned above. + * pcb2->pcb_onfault: cloned above (always NULL here?). + * pcb2->pcb_[fg]sbase: cloned above + */ + + /* Setup to release spin count in fork_exit(). */ + td2->td_md.md_spinlock_count = 1; + td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; + pmap_thread_init_invl_gen(td2); +} + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -164,36 +223,13 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) return; } - /* Ensure that td1's pcb is up to date for user processes. */ - if ((td2->td_pflags & TDP_KTHREAD) == 0) { - MPASS(td1 == curthread); - fpuexit(td1); - update_pcb_bases(td1->td_pcb); - } - /* Point the stack and pcb to the actual location */ set_top_of_stack_td(td2); td2->td_pcb = pcb2 = get_pcb_td(td2); - /* Copy td1's pcb */ - bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); - - /* Properly initialize pcb_save */ - pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); + copy_thread(td1, td2); - /* Kernel processes start with clean FPU and segment bases. */ - if ((td2->td_pflags & TDP_KTHREAD) != 0) { - pcb2->pcb_fsbase = 0; - pcb2->pcb_gsbase = 0; - clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE | - PCB_KERNFPU | PCB_KERNFPU_THR); - } else { - MPASS((pcb2->pcb_flags & (PCB_KERNFPU | PCB_KERNFPU_THR)) == 0); - bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), - cpu_max_ext_state_size); - } - - /* Point mdproc and then copy over td1's contents */ + /* Point mdproc and then copy over p1's contents */ mdp2 = &p2->p_md; bcopy(&p1->p_md, mdp2, sizeof(*mdp2)); @@ -215,29 +251,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) */ td2->td_frame->tf_rflags &= ~PSL_T; - /* - * Set registers for trampoline to user mode. Leave space for the - * return address on stack. These are the kernel mode register values. - */ - pcb2->pcb_r12 = (register_t)fork_return; /* fork_trampoline argument */ - pcb2->pcb_rbp = 0; - pcb2->pcb_rsp = (register_t)td2->td_frame - sizeof(void *); - pcb2->pcb_rbx = (register_t)td2; /* fork_trampoline argument */ - pcb2->pcb_rip = (register_t)fork_trampoline; - /*- - * pcb2->pcb_dr*: cloned above. - * pcb2->pcb_savefpu: cloned above. - * pcb2->pcb_flags: cloned above. - * pcb2->pcb_onfault: cloned above (always NULL here?). - * pcb2->pcb_[fg]sbase: cloned above - */ - - /* Setup to release spin count in fork_exit(). */ - td2->td_md.md_spinlock_count = 1; - td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; - pmap_thread_init_invl_gen(td2); - - /* As an i386, do not copy io permission bitmap. */ + /* As on i386, do not copy io permission bitmap. */ pcb2->pcb_tssp = NULL; /* New segment registers. */ @@ -275,7 +289,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) * pcb_rsp is loaded pointing to the cpu_switch() stack frame * containing the return address when exiting cpu_switch. * This will normally be to fork_trampoline(), which will have - * %ebx loaded with the new proc's pointer. fork_trampoline() + * %rbx loaded with the new proc's pointer. fork_trampoline() * will set up a stack to call fork_return(p, frame); to complete * the return to user-mode. */ @@ -571,38 +585,7 @@ cpu_set_syscall_retval(struct thread *td, int error) void cpu_copy_thread(struct thread *td, struct thread *td0) { - struct pcb *pcb2; - - pcb2 = td->td_pcb; - - /* Ensure that td0's pcb is up to date for user threads. */ - if ((td->td_pflags & TDP_KTHREAD) == 0) { - MPASS(td0 == curthread); - fpuexit(td0); - update_pcb_bases(td0->td_pcb); - } - - /* - * Copy the upcall pcb. This loads kernel regs. - * Those not loaded individually below get their default - * values here. - */ - bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); - pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); - - /* Kernel threads start with clean FPU and segment bases. */ - if ((td->td_pflags & TDP_KTHREAD) != 0) { - pcb2->pcb_fsbase = 0; - pcb2->pcb_gsbase = 0; - clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE | - PCB_KERNFPU | PCB_KERNFPU_THR); - } else { - MPASS((pcb2->pcb_flags & (PCB_KERNFPU | PCB_KERNFPU_THR)) == 0); - bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save, - cpu_max_ext_state_size); - } - set_pcb_flags_raw(pcb2, PCB_FULL_IRET); - + copy_thread(td0, td); /* * Copy user general-purpose registers. @@ -620,27 +603,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0) */ td->td_frame->tf_rflags &= ~PSL_T; - /* - * Set registers for trampoline to user mode. Leave space for the - * return address on stack. These are the kernel mode register values. - */ - pcb2->pcb_r12 = (register_t)fork_return; /* trampoline arg */ - pcb2->pcb_rbp = 0; - pcb2->pcb_rsp = (register_t)td->td_frame - sizeof(void *); /* trampoline arg */ - pcb2->pcb_rbx = (register_t)td; /* trampoline arg */ - pcb2->pcb_rip = (register_t)fork_trampoline; - /* - * If we didn't copy the pcb, we'd need to do the following registers: - * pcb2->pcb_dr*: cloned above. - * pcb2->pcb_savefpu: cloned above. - * pcb2->pcb_onfault: cloned above (always NULL here?). - * pcb2->pcb_[fg]sbase: cloned above - */ - - /* Setup to release spin count in fork_exit(). */ - td->td_md.md_spinlock_count = 1; - td->td_md.md_saved_flags = PSL_KERNEL | PSL_I; - pmap_thread_init_invl_gen(td); + set_pcb_flags_raw(td->td_pcb, PCB_FULL_IRET); } /* diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c index 5947ae5a6d15..5bbdfdb77b2d 100644 --- a/sys/i386/i386/vm_machdep.c +++ b/sys/i386/i386/vm_machdep.c @@ -133,6 +133,74 @@ alloc_fpusave(int flags) } return (res); } + +/* + * Common code shared between cpu_fork() and cpu_copy_thread() for + * initializing a thread. + */ +static void +copy_thread(struct thread *td1, struct thread *td2) +{ + struct pcb *pcb2; + + pcb2 = td2->td_pcb; + + /* Ensure that td1's pcb is up to date for user threads. */ + if ((td2->td_pflags & TDP_KTHREAD) == 0) { + MPASS(td1 == curthread); + td1->td_pcb->pcb_gs = rgs(); + critical_enter(); + if (PCPU_GET(fpcurthread) == td1) + npxsave(td1->td_pcb->pcb_save); + critical_exit(); + } + + /* Copy td1's pcb */ + bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); + + /* Properly initialize pcb_save */ + pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); + + /* Kernel threads start with clean NPX and segment bases. */ + if ((td2->td_pflags & TDP_KTHREAD) != 0) { + pcb2->pcb_gs = _udatasel; + set_fsbase(td2, 0); + set_gsbase(td2, 0); + pcb2->pcb_flags &= ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE | + PCB_KERNNPX | PCB_KERNNPX_THR); + } else { + MPASS((pcb2->pcb_flags & (PCB_KERNNPX | PCB_KERNNPX_THR)) == 0); + bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), + cpu_max_ext_state_size); + } + + /* + * Set registers for trampoline to user mode. Leave space for the + * return address on stack. These are the kernel mode register values. + */ + pcb2->pcb_edi = 0; + pcb2->pcb_esi = (int)fork_return; /* trampoline arg */ + pcb2->pcb_ebp = 0; + pcb2->pcb_esp = (int)td2->td_frame - sizeof(void *); /* trampoline arg */ + pcb2->pcb_ebx = (int)td2; /* trampoline arg */ + pcb2->pcb_eip = (int)fork_trampoline + setidt_disp; + /* + * If we didn't copy the pcb, we'd need to do the following registers: + * pcb2->pcb_cr3: cloned above. + * pcb2->pcb_dr*: cloned above. + * pcb2->pcb_savefpu: cloned above. + * pcb2->pcb_flags: cloned above. + * pcb2->pcb_onfault: cloned above (always NULL here?). + * pcb2->pcb_gs: cloned above. + * pcb2->pcb_ext: cleared below. + */ + pcb2->pcb_ext = NULL; + + /* Setup to release spin count in fork_exit(). */ + td2->td_md.md_spinlock_count = 1; + td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; +} + /* * Finish a fork operation, with process p2 nearly set up. * Copy and update the pcb, set up the stack so that the child @@ -167,38 +235,11 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) return; } - /* Ensure that td1's pcb is up to date for user processes. */ - if ((td2->td_pflags & TDP_KTHREAD) == 0) { - MPASS(td1 == curthread); - td1->td_pcb->pcb_gs = rgs(); - critical_enter(); - if (PCPU_GET(fpcurthread) == td1) - npxsave(td1->td_pcb->pcb_save); - critical_exit(); - } - /* Point the pcb to the top of the stack */ pcb2 = get_pcb_td(td2); td2->td_pcb = pcb2; - /* Copy td1's pcb */ - bcopy(td1->td_pcb, pcb2, sizeof(*pcb2)); - - /* Properly initialize pcb_save */ - pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); - - /* Kernel processes start with clean NPX and segment bases. */ - if ((td2->td_pflags & TDP_KTHREAD) != 0) { - pcb2->pcb_gs = _udatasel; - set_fsbase(td2, 0); - set_gsbase(td2, 0); - pcb2->pcb_flags &= ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE | - PCB_KERNNPX | PCB_KERNNPX_THR); - } else { - MPASS((pcb2->pcb_flags & (PCB_KERNNPX | PCB_KERNNPX_THR)) == 0); - bcopy(get_pcb_user_save_td(td1), get_pcb_user_save_pcb(pcb2), - cpu_max_ext_state_size); - } + copy_thread(td1, td2); /* Point mdproc and then copy over td1's contents */ mdp2 = &p2->p_md; @@ -225,30 +266,13 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) */ td2->td_frame->tf_eflags &= ~PSL_T; - /* - * Set registers for trampoline to user mode. Leave space for the - * return address on stack. These are the kernel mode register values. - */ + /* Set cr3 for the new process. */ pcb2->pcb_cr3 = pmap_get_cr3(vmspace_pmap(p2->p_vmspace)); - pcb2->pcb_edi = 0; - pcb2->pcb_esi = (int)fork_return; /* fork_trampoline argument */ - pcb2->pcb_ebp = 0; - pcb2->pcb_esp = (int)td2->td_frame - sizeof(void *); - pcb2->pcb_ebx = (int)td2; /* fork_trampoline argument */ - pcb2->pcb_eip = (int)fork_trampoline + setidt_disp; - /*- - * pcb2->pcb_dr*: cloned above. - * pcb2->pcb_savefpu: cloned above. - * pcb2->pcb_flags: cloned above. - * pcb2->pcb_onfault: cloned above (always NULL here?). - * pcb2->pcb_gs: cloned above. - * pcb2->pcb_ext: cleared below. - */ /* * XXX don't copy the i/o pages. this should probably be fixed. */ - pcb2->pcb_ext = 0; + pcb2->pcb_ext = NULL; /* Copy the LDT, if necessary. */ mtx_lock_spin(&dt_lock); @@ -264,10 +288,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) } mtx_unlock_spin(&dt_lock); - /* Setup to release spin count in fork_exit(). */ - td2->td_md.md_spinlock_count = 1; - td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I; - /* * Now, cpu_switch() can schedule the new process. * pcb_esp is loaded pointing to the cpu_switch() stack frame @@ -435,41 +455,7 @@ cpu_set_syscall_retval(struct thread *td, int error) void cpu_copy_thread(struct thread *td, struct thread *td0) { - struct pcb *pcb2; - - /* Point the pcb to the top of the stack. */ - pcb2 = td->td_pcb; - - /* Ensure that td0's pcb is up to date for user threads. */ - if ((td->td_pflags & TDP_KTHREAD) == 0) { - MPASS(td0 == curthread); - td0->td_pcb->pcb_gs = rgs(); - critical_enter(); - if (PCPU_GET(fpcurthread) == td0) - npxsave(td0->td_pcb->pcb_save); - critical_exit(); - } - - /* - * Copy the upcall pcb. This loads kernel regs. - * Those not loaded individually below get their default - * values here. - */ - bcopy(td0->td_pcb, pcb2, sizeof(*pcb2)); - pcb2->pcb_save = get_pcb_user_save_pcb(pcb2); - - /* Kernel threads start with clean NPX and segment bases. */ - if ((td->td_pflags & TDP_KTHREAD) != 0) { - pcb2->pcb_gs = _udatasel; - set_fsbase(td, 0); - set_gsbase(td, 0); - pcb2->pcb_flags &= ~(PCB_NPXINITDONE | PCB_NPXUSERINITDONE | - PCB_KERNNPX | PCB_KERNNPX_THR); - } else { - MPASS((pcb2->pcb_flags & (PCB_KERNNPX | PCB_KERNNPX_THR)) == 0); - bcopy(get_pcb_user_save_td(td0), pcb2->pcb_save, - cpu_max_ext_state_size); - } + copy_thread(td0, td); /* * Copy user general-purpose registers. @@ -486,32 +472,6 @@ cpu_copy_thread(struct thread *td, struct thread *td0) * instruction after returning to userland. */ td->td_frame->tf_eflags &= ~PSL_T; - - /* - * Set registers for trampoline to user mode. Leave space for the - * return address on stack. These are the kernel mode register values. - */ - pcb2->pcb_edi = 0; - pcb2->pcb_esi = (int)fork_return; /* trampoline arg */ - pcb2->pcb_ebp = 0; - pcb2->pcb_esp = (int)td->td_frame - sizeof(void *); /* trampoline arg */ - pcb2->pcb_ebx = (int)td; /* trampoline arg */ - pcb2->pcb_eip = (int)fork_trampoline + setidt_disp; - /* - * If we didn't copy the pcb, we'd need to do the following registers: - * pcb2->pcb_cr3: cloned above. - * pcb2->pcb_dr*: cloned above. - * pcb2->pcb_savefpu: cloned above. - * pcb2->pcb_flags: cloned above. - * pcb2->pcb_onfault: cloned above (always NULL here?). - * pcb2->pcb_gs: cloned above. - * pcb2->pcb_ext: cleared below. - */ - pcb2->pcb_ext = NULL; - - /* Setup to release spin count in fork_exit(). */ - td->td_md.md_spinlock_count = 1; - td->td_md.md_saved_flags = PSL_KERNEL | PSL_I; } /*