10967373eSDavid Greenman/*- 20967373eSDavid Greenman * Copyright (c) 1990 The Regents of the University of California. 30967373eSDavid Greenman * All rights reserved. 40967373eSDavid Greenman * 50967373eSDavid Greenman * This code is derived from software contributed to Berkeley by 60967373eSDavid Greenman * William Jolitz. 70967373eSDavid Greenman * 80967373eSDavid Greenman * Redistribution and use in source and binary forms, with or without 90967373eSDavid Greenman * modification, are permitted provided that the following conditions 100967373eSDavid Greenman * are met: 110967373eSDavid Greenman * 1. Redistributions of source code must retain the above copyright 120967373eSDavid Greenman * notice, this list of conditions and the following disclaimer. 130967373eSDavid Greenman * 2. Redistributions in binary form must reproduce the above copyright 140967373eSDavid Greenman * notice, this list of conditions and the following disclaimer in the 150967373eSDavid Greenman * documentation and/or other materials provided with the distribution. 160967373eSDavid Greenman * 3. All advertising materials mentioning features or use of this software 170967373eSDavid Greenman * must display the following acknowledgement: 180967373eSDavid Greenman * This product includes software developed by the University of 190967373eSDavid Greenman * California, Berkeley and its contributors. 200967373eSDavid Greenman * 4. Neither the name of the University nor the names of its contributors 210967373eSDavid Greenman * may be used to endorse or promote products derived from this software 220967373eSDavid Greenman * without specific prior written permission. 230967373eSDavid Greenman * 240967373eSDavid Greenman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 250967373eSDavid Greenman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 260967373eSDavid Greenman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 270967373eSDavid Greenman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 280967373eSDavid Greenman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 290967373eSDavid Greenman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 300967373eSDavid Greenman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 310967373eSDavid Greenman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 320967373eSDavid Greenman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 330967373eSDavid Greenman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 340967373eSDavid Greenman * SUCH DAMAGE. 350967373eSDavid Greenman * 36c3aac50fSPeter Wemm * $FreeBSD$ 370967373eSDavid Greenman */ 380967373eSDavid Greenman 39558226eaSPeter Wemm#include "opt_npx.h" 400967373eSDavid Greenman 410513ce7fSBruce Evans#include <machine/asmacros.h> 42477a642cSPeter Wemm 43665bb8faSSteve Passe#ifdef SMP 44b3196e4bSPeter Wemm#include <machine/apic.h> 45163fd6fbSJohn Baldwin#include <machine/smptests.h> /* CHEAP_TPR, GRAB_LOPRIO */ 469869fa1dSJohn Baldwin#endif 470513ce7fSBruce Evans 480513ce7fSBruce Evans#include "assym.s" 490513ce7fSBruce Evans 500967373eSDavid Greenman/*****************************************************************************/ 510967373eSDavid Greenman/* Scheduling */ 520967373eSDavid Greenman/*****************************************************************************/ 530967373eSDavid Greenman 540967373eSDavid Greenman .data 55665bb8faSSteve Passe 5602318dacSJake Burkholder .globl panic 570967373eSDavid Greenman 5882566551SJohn Dyson#if defined(SWTCH_OPTIM_STATS) 5902318dacSJake Burkholder .globl swtch_optim_stats, tlb_flush_count 6002318dacSJake Burkholderswtch_optim_stats: .long 0 /* number of _swtch_optims */ 6102318dacSJake Burkholdertlb_flush_count: .long 0 6282566551SJohn Dyson#endif 630967373eSDavid Greenman 640967373eSDavid Greenman .text 650967373eSDavid Greenman 660967373eSDavid Greenman/* 670384fff8SJason Evans * cpu_throw() 680384fff8SJason Evans */ 690384fff8SJason EvansENTRY(cpu_throw) 700384fff8SJason Evans jmp sw1 710384fff8SJason Evans 720384fff8SJason Evans/* 7326f9a767SRodney W. Grimes * cpu_switch() 740967373eSDavid Greenman */ 7526f9a767SRodney W. GrimesENTRY(cpu_switch) 76477a642cSPeter Wemm 779869fa1dSJohn Baldwin /* Switch to new thread. First, save context as needed. */ 78b40ce416SJulian Elischer movl PCPU(CURTHREAD),%ecx 790967373eSDavid Greenman 809869fa1dSJohn Baldwin /* If no thread to save, don't save it (XXX shouldn't happen). */ 810967373eSDavid Greenman testl %ecx,%ecx 820384fff8SJason Evans jz sw1 83163fd6fbSJohn Baldwin 84b40ce416SJulian Elischer movl TD_PROC(%ecx), %eax 85b40ce416SJulian Elischer movl P_VMSPACE(%eax), %edx 866d43764aSJake Burkholder movl PCPU(CPUID), %eax 87087e80a9SAlan Cox btrl %eax, VM_PMAP+PM_ACTIVE(%edx) 88477a642cSPeter Wemm 89b40ce416SJulian Elischer movl TD_PCB(%ecx),%edx 900967373eSDavid Greenman 911b00f920SJake Burkholder movl (%esp),%eax /* Hardware registers */ 921b00f920SJake Burkholder movl %eax,PCB_EIP(%edx) 93087e80a9SAlan Cox movl %ebx,PCB_EBX(%edx) 94087e80a9SAlan Cox movl %esp,PCB_ESP(%edx) 95087e80a9SAlan Cox movl %ebp,PCB_EBP(%edx) 96087e80a9SAlan Cox movl %esi,PCB_ESI(%edx) 97087e80a9SAlan Cox movl %edi,PCB_EDI(%edx) 98087e80a9SAlan Cox movl %gs,PCB_GS(%edx) 990967373eSDavid Greenman 100163fd6fbSJohn Baldwin /* Test if debug registers should be saved. */ 101ab001a72SJonathan Lemon movb PCB_FLAGS(%edx),%al 102ab001a72SJonathan Lemon andb $PCB_DBREGS,%al 103ab001a72SJonathan Lemon jz 1f /* no, skip over */ 104ab001a72SJonathan Lemon movl %dr7,%eax /* yes, do the save */ 105ab001a72SJonathan Lemon movl %eax,PCB_DR7(%edx) 1063ad234d4SBrian S. Dean andl $0x0000fc00, %eax /* disable all watchpoints */ 107ab001a72SJonathan Lemon movl %eax,%dr7 108ab001a72SJonathan Lemon movl %dr6,%eax 109ab001a72SJonathan Lemon movl %eax,PCB_DR6(%edx) 110ab001a72SJonathan Lemon movl %dr3,%eax 111ab001a72SJonathan Lemon movl %eax,PCB_DR3(%edx) 112ab001a72SJonathan Lemon movl %dr2,%eax 113ab001a72SJonathan Lemon movl %eax,PCB_DR2(%edx) 114ab001a72SJonathan Lemon movl %dr1,%eax 115ab001a72SJonathan Lemon movl %eax,PCB_DR1(%edx) 116ab001a72SJonathan Lemon movl %dr0,%eax 117ab001a72SJonathan Lemon movl %eax,PCB_DR0(%edx) 118ab001a72SJonathan Lemon1: 119ab001a72SJonathan Lemon 120477a642cSPeter Wemm#ifdef SMP 121da9f0182SSteve Passe /* XXX FIXME: we should be saving the local APIC TPR */ 1229869fa1dSJohn Baldwin#endif 123477a642cSPeter Wemm 124558226eaSPeter Wemm#ifdef DEV_NPX 1250967373eSDavid Greenman /* have we used fp, and need a save? */ 126b40ce416SJulian Elischer cmpl %ecx,PCPU(NPXTHREAD) 1270967373eSDavid Greenman jne 1f 128087e80a9SAlan Cox addl $PCB_SAVEFPU,%edx /* h/w bugs make saving complicated */ 129087e80a9SAlan Cox pushl %edx 13002318dacSJake Burkholder call npxsave /* do it in a big C function */ 1310967373eSDavid Greenman popl %eax 1320967373eSDavid Greenman1: 1339869fa1dSJohn Baldwin#endif 1340967373eSDavid Greenman 135163fd6fbSJohn Baldwin /* Save is done. Now choose a new thread. */ 136163fd6fbSJohn Baldwin /* XXX still trashing space above the old "Top Of Stack". */ 1370967373eSDavid Greenmansw1: 1389a3b3e8bSPeter Wemm 1399a3b3e8bSPeter Wemm#ifdef SMP 1409869fa1dSJohn Baldwin /* 1419869fa1dSJohn Baldwin * Stop scheduling if smp_active has become zero (for rebooting) and 1429869fa1dSJohn Baldwin * we are not the BSP. 1439869fa1dSJohn Baldwin */ 14402318dacSJake Burkholder cmpl $0,smp_active 1459a3b3e8bSPeter Wemm jne 1f 1466d43764aSJake Burkholder cmpl $0,PCPU(CPUID) 1470384fff8SJason Evans je 1f 148b40ce416SJulian Elischer movl PCPU(IDLETHREAD), %eax 149163fd6fbSJohn Baldwin jmp sw1b 1509a3b3e8bSPeter Wemm1: 1519a3b3e8bSPeter Wemm#endif 1529a3b3e8bSPeter Wemm 1530384fff8SJason Evans /* 154163fd6fbSJohn Baldwin * Choose a new thread to schedule. choosethread() returns idlethread 155163fd6fbSJohn Baldwin * if it cannot find another thread to run. 1560384fff8SJason Evans */ 1579869fa1dSJohn Baldwin call choosethread /* Trash ecx, edx; ret eax. */ 1580384fff8SJason Evans 159835a748fSJohn Baldwin#ifdef INVARIANTS 160163fd6fbSJohn Baldwin testl %eax,%eax /* no thread? */ 1610384fff8SJason Evans jz badsw3 /* no, panic */ 1620384fff8SJason Evans#endif 163163fd6fbSJohn Baldwin 1640384fff8SJason Evanssw1b: 16528f31ccfSPeter Wemm movl %eax,%ecx 1667216391eSDavid Greenman 167835a748fSJohn Baldwin#ifdef INVARIANTS 168b40ce416SJulian Elischer movl TD_PROC(%ecx), %eax /* XXXKSE */ 169b40ce416SJulian Elischer cmpb $SRUN,P_STAT(%eax) 170b3196e4bSPeter Wemm jne badsw2 1710967373eSDavid Greenman#endif 1720967373eSDavid Greenman 173b40ce416SJulian Elischer movl TD_PCB(%ecx),%edx 1740967373eSDavid Greenman 17582566551SJohn Dyson#if defined(SWTCH_OPTIM_STATS) 17602318dacSJake Burkholder incl swtch_optim_stats 17782566551SJohn Dyson#endif 178b40ce416SJulian Elischer 1790967373eSDavid Greenman /* switch address space */ 18082566551SJohn Dyson movl %cr3,%ebx 18182566551SJohn Dyson cmpl PCB_CR3(%edx),%ebx 18282566551SJohn Dyson je 4f 18382566551SJohn Dyson#if defined(SWTCH_OPTIM_STATS) 18402318dacSJake Burkholder decl swtch_optim_stats 18502318dacSJake Burkholder incl tlb_flush_count 18682566551SJohn Dyson#endif 18782566551SJohn Dyson movl PCB_CR3(%edx),%ebx 1889869fa1dSJohn Baldwin movl %ebx,%cr3 18982566551SJohn Dyson4: 190163fd6fbSJohn Baldwin 1916d43764aSJake Burkholder movl PCPU(CPUID), %esi 19248a09cf2SJohn Dyson cmpl $0, PCB_EXT(%edx) /* has pcb extension? */ 19348a09cf2SJohn Dyson je 1f 19402318dacSJake Burkholder btsl %esi, private_tss /* mark use of private tss */ 19548a09cf2SJohn Dyson movl PCB_EXT(%edx), %edi /* new tss descriptor */ 19648a09cf2SJohn Dyson jmp 2f 19748a09cf2SJohn Dyson1: 1989869fa1dSJohn Baldwin 1999869fa1dSJohn Baldwin /* Update common_tss.tss_esp0 pointer. */ 2002f01a0c0SPeter Wemm leal -16(%edx), %ebx /* leave space for vm86 */ 2012f01a0c0SPeter Wemm movl %ebx, PCPU(COMMON_TSS) + TSS_ESP0 /* stack is below pcb */ 202163fd6fbSJohn Baldwin 20302318dacSJake Burkholder btrl %esi, private_tss 2045206bca1SLuoqi Chen jae 3f 20541ed17bfSJake Burkholder PCPU_ADDR(COMMON_TSSD, %edi) 20648a09cf2SJohn Dyson2: 207163fd6fbSJohn Baldwin /* Move correct tss descriptor into GDT slot, then reload tr. */ 2086d43764aSJake Burkholder movl PCPU(TSS_GDT), %ebx /* entry in GDT */ 20948a09cf2SJohn Dyson movl 0(%edi), %eax 21048a09cf2SJohn Dyson movl %eax, 0(%ebx) 21148a09cf2SJohn Dyson movl 4(%edi), %eax 21248a09cf2SJohn Dyson movl %eax, 4(%ebx) 2130f0fe5a4SLuoqi Chen movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */ 21448a09cf2SJohn Dyson ltr %si 21548a09cf2SJohn Dyson3: 2169869fa1dSJohn Baldwin /* Note in vmspace that this cpu is using it. */ 217163fd6fbSJohn Baldwin movl TD_PROC(%ecx),%eax /* XXXKSE proc from thread */ 218163fd6fbSJohn Baldwin movl P_VMSPACE(%eax), %ebx 2196d43764aSJake Burkholder movl PCPU(CPUID), %eax 220087e80a9SAlan Cox btsl %eax, VM_PMAP+PM_ACTIVE(%ebx) 221a2a1c95cSPeter Wemm 2229869fa1dSJohn Baldwin /* Restore context. */ 2230967373eSDavid Greenman movl PCB_EBX(%edx),%ebx 2240967373eSDavid Greenman movl PCB_ESP(%edx),%esp 2250967373eSDavid Greenman movl PCB_EBP(%edx),%ebp 2260967373eSDavid Greenman movl PCB_ESI(%edx),%esi 2270967373eSDavid Greenman movl PCB_EDI(%edx),%edi 2281b00f920SJake Burkholder movl PCB_EIP(%edx),%eax 2291b00f920SJake Burkholder movl %eax,(%esp) 2300967373eSDavid Greenman 2319869fa1dSJohn Baldwin#if defined(SMP) && defined(GRAP_LOPRIO) 2329869fa1dSJohn Baldwin /* Hold LOPRIO for interrupts. */ 233570dbb53SSteve Passe#ifdef CHEAP_TPR 23402318dacSJake Burkholder movl $0, lapic+LA_TPR 235570dbb53SSteve Passe#else 23602318dacSJake Burkholder andl $~APIC_TPR_PRIO, lapic+LA_TPR 2379869fa1dSJohn Baldwin#endif 2389869fa1dSJohn Baldwin#endif 2396d43764aSJake Burkholder movl %edx, PCPU(CURPCB) 240163fd6fbSJohn Baldwin movl %ecx, PCPU(CURTHREAD) /* into next thread */ 241477a642cSPeter Wemm 242477a642cSPeter Wemm#ifdef SMP 243da9f0182SSteve Passe /* XXX FIXME: we should be restoring the local APIC TPR */ 2449869fa1dSJohn Baldwin#endif 2450967373eSDavid Greenman 2469869fa1dSJohn Baldwin /* 2479869fa1dSJohn Baldwin * Determine the LDT to use and load it if is the default one and 2489869fa1dSJohn Baldwin * that is not the current one. 2499869fa1dSJohn Baldwin */ 250163fd6fbSJohn Baldwin movl TD_PROC(%ecx),%eax 2519869fa1dSJohn Baldwin cmpl $0,P_MD+MD_LDT(%eax) 2529869fa1dSJohn Baldwin jnz 1f 2539869fa1dSJohn Baldwin movl _default_ldt,%eax 254163fd6fbSJohn Baldwin cmpl PCPU(CURRENTLDT),%eax 255163fd6fbSJohn Baldwin je 2f 256163fd6fbSJohn Baldwin lldt _default_ldt 257163fd6fbSJohn Baldwin movl %eax,PCPU(CURRENTLDT) 258da59a31cSDavid Greenman jmp 2f 2599869fa1dSJohn Baldwin1: 2609869fa1dSJohn Baldwin /* Load the LDT when it is not the default one. */ 2619869fa1dSJohn Baldwin pushl %edx /* Preserve pointer to pcb. */ 2627df8a724SJohn Baldwin addl $P_MD,%eax /* Pointer to mdproc is arg. */ 2637df8a724SJohn Baldwin pushl %eax 2649869fa1dSJohn Baldwin call set_user_ldt 2657df8a724SJohn Baldwin addl $4,%esp 266163fd6fbSJohn Baldwin popl %edx 267da59a31cSDavid Greenman2: 268da59a31cSDavid Greenman 2697b3c8424SBruce Evans /* This must be done after loading the user LDT. */ 2707b3c8424SBruce Evans .globl cpu_switch_load_gs 2717b3c8424SBruce Evanscpu_switch_load_gs: 2727b3c8424SBruce Evans movl PCB_GS(%edx),%gs 2737b3c8424SBruce Evans 2749869fa1dSJohn Baldwin /* Test if debug regisers should be restored. */ 275ab001a72SJonathan Lemon movb PCB_FLAGS(%edx),%al 276ab001a72SJonathan Lemon andb $PCB_DBREGS,%al 2779869fa1dSJohn Baldwin jz 1f 2789869fa1dSJohn Baldwin 2799869fa1dSJohn Baldwin /* 2809869fa1dSJohn Baldwin * Restore debug registers. The special code for dr7 is to 2819869fa1dSJohn Baldwin * preserve the current values of its reserved bits. 2829869fa1dSJohn Baldwin */ 2839869fa1dSJohn Baldwin movl PCB_DR6(%edx),%eax 284ab001a72SJonathan Lemon movl %eax,%dr6 285ab001a72SJonathan Lemon movl PCB_DR3(%edx),%eax 286ab001a72SJonathan Lemon movl %eax,%dr3 287ab001a72SJonathan Lemon movl PCB_DR2(%edx),%eax 288ab001a72SJonathan Lemon movl %eax,%dr2 289ab001a72SJonathan Lemon movl PCB_DR1(%edx),%eax 290ab001a72SJonathan Lemon movl %eax,%dr1 291ab001a72SJonathan Lemon movl PCB_DR0(%edx),%eax 292ab001a72SJonathan Lemon movl %eax,%dr0 2939869fa1dSJohn Baldwin movl %dr7,%eax 2949869fa1dSJohn Baldwin andl $0x0000fc00,%eax 29502c41f11SJohn Baldwin movl PCB_DR7(%edx),%ecx 2969869fa1dSJohn Baldwin andl $~0x0000fc00,%ecx 29702c41f11SJohn Baldwin orl %ecx,%eax 298ab001a72SJonathan Lemon movl %eax,%dr7 299ab001a72SJonathan Lemon1: 3000967373eSDavid Greenman ret 3010967373eSDavid Greenman 302835a748fSJohn Baldwin#ifdef INVARIANTS 303b3196e4bSPeter Wemmbadsw2: 304b3196e4bSPeter Wemm pushl $sw0_2 30502318dacSJake Burkholder call panic 306b3196e4bSPeter Wemm 307b3196e4bSPeter Wemmsw0_2: .asciz "cpu_switch: not SRUN" 308b3196e4bSPeter Wemm 3090384fff8SJason Evansbadsw3: 3100384fff8SJason Evans pushl $sw0_3 31102318dacSJake Burkholder call panic 312b3196e4bSPeter Wemm 313163fd6fbSJohn Baldwinsw0_3: .asciz "cpu_switch: choosethread returned NULL" 3140384fff8SJason Evans#endif 315ebd707d3SBruce Evans 3160967373eSDavid Greenman/* 3172924d491SDavid Greenman * savectx(pcb) 3182924d491SDavid Greenman * Update pcb, saving current processor state. 3190967373eSDavid Greenman */ 3200967373eSDavid GreenmanENTRY(savectx) 3219869fa1dSJohn Baldwin /* Fetch PCB. */ 3220967373eSDavid Greenman movl 4(%esp),%ecx 3232924d491SDavid Greenman 3249869fa1dSJohn Baldwin /* Save caller's return address. Child won't execute this routine. */ 3250967373eSDavid Greenman movl (%esp),%eax 3260967373eSDavid Greenman movl %eax,PCB_EIP(%ecx) 3272924d491SDavid Greenman 328ac5f943cSPeter Wemm movl %cr3,%eax 329ac5f943cSPeter Wemm movl %eax,PCB_CR3(%ecx) 330ac5f943cSPeter Wemm 3310967373eSDavid Greenman movl %ebx,PCB_EBX(%ecx) 332ac474627SDavid Greenman movl %esp,PCB_ESP(%ecx) 3330967373eSDavid Greenman movl %ebp,PCB_EBP(%ecx) 3340967373eSDavid Greenman movl %esi,PCB_ESI(%ecx) 3350967373eSDavid Greenman movl %edi,PCB_EDI(%ecx) 3367b3c8424SBruce Evans movl %gs,PCB_GS(%ecx) 3370967373eSDavid Greenman 338558226eaSPeter Wemm#ifdef DEV_NPX 3390967373eSDavid Greenman /* 340b40ce416SJulian Elischer * If npxthread == NULL, then the npx h/w state is irrelevant and the 3410967373eSDavid Greenman * state had better already be in the pcb. This is true for forks 3420967373eSDavid Greenman * but not for dumps (the old book-keeping with FP flags in the pcb 3430967373eSDavid Greenman * always lost for dumps because the dump pcb has 0 flags). 3440967373eSDavid Greenman * 345b40ce416SJulian Elischer * If npxthread != NULL, then we have to save the npx h/w state to 346b40ce416SJulian Elischer * npxthread's pcb and copy it to the requested pcb, or save to the 3470967373eSDavid Greenman * requested pcb and reload. Copying is easier because we would 3480967373eSDavid Greenman * have to handle h/w bugs for reloading. We used to lose the 3490967373eSDavid Greenman * parent's npx state for forks by forgetting to reload. 3500967373eSDavid Greenman */ 351c2b095abSBruce Evans pushfl 352c2b095abSBruce Evans cli 353b40ce416SJulian Elischer movl PCPU(NPXTHREAD),%eax 3540967373eSDavid Greenman testl %eax,%eax 3550967373eSDavid Greenman je 1f 3560967373eSDavid Greenman 3570967373eSDavid Greenman pushl %ecx 358b40ce416SJulian Elischer movl TD_PCB(%eax),%eax 3590967373eSDavid Greenman leal PCB_SAVEFPU(%eax),%eax 3600967373eSDavid Greenman pushl %eax 3610967373eSDavid Greenman pushl %eax 36202318dacSJake Burkholder call npxsave 363eabe0f9fSBruce Evans addl $4,%esp 3640967373eSDavid Greenman popl %eax 3650967373eSDavid Greenman popl %ecx 3660967373eSDavid Greenman 3670513ce7fSBruce Evans pushl $PCB_SAVEFPU_SIZE 3680967373eSDavid Greenman leal PCB_SAVEFPU(%ecx),%ecx 3690967373eSDavid Greenman pushl %ecx 3700967373eSDavid Greenman pushl %eax 37102318dacSJake Burkholder call bcopy 3720967373eSDavid Greenman addl $12,%esp 373c2b095abSBruce Evans1: 374c2b095abSBruce Evans popfl 375558226eaSPeter Wemm#endif /* DEV_NPX */ 3760967373eSDavid Greenman 3770967373eSDavid Greenman ret 378