| Commit | Line | Data |
|---|---|---|
| 8c10bfcf MD |
1 | /* |
| 2 | * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in | |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 32 | * SUCH DAMAGE. | |
| 33 | * | |
| 984263bc MD |
34 | * Copyright (c) 1990 The Regents of the University of California. |
| 35 | * All rights reserved. | |
| 36 | * | |
| 37 | * This code is derived from software contributed to Berkeley by | |
| 38 | * William Jolitz. | |
| 39 | * | |
| 40 | * Redistribution and use in source and binary forms, with or without | |
| 41 | * modification, are permitted provided that the following conditions | |
| 42 | * are met: | |
| 43 | * 1. Redistributions of source code must retain the above copyright | |
| 44 | * notice, this list of conditions and the following disclaimer. | |
| 45 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 46 | * notice, this list of conditions and the following disclaimer in the | |
| 47 | * documentation and/or other materials provided with the distribution. | |
| 48 | * 3. All advertising materials mentioning features or use of this software | |
| 49 | * must display the following acknowledgement: | |
| 50 | * This product includes software developed by the University of | |
| 51 | * California, Berkeley and its contributors. | |
| 52 | * 4. Neither the name of the University nor the names of its contributors | |
| 53 | * may be used to endorse or promote products derived from this software | |
| 54 | * without specific prior written permission. | |
| 55 | * | |
| 56 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 57 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 58 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 59 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 60 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 61 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 62 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 63 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 64 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 65 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 66 | * SUCH DAMAGE. | |
| 67 | * | |
| 68 | * $FreeBSD: src/sys/i386/i386/swtch.s,v 1.89.2.10 2003/01/23 03:36:24 ps Exp $ | |
| 287ebb09 | 69 | * $DragonFly: src/sys/platform/pc32/i386/swtch.s,v 1.47 2007/06/29 21:54:10 dillon Exp $ |
| 984263bc MD |
70 | */ |
| 71 | ||
| 1f2de5d4 | 72 | #include "use_npx.h" |
| 984263bc MD |
73 | |
| 74 | #include <sys/rtprio.h> | |
| 75 | ||
| 76 | #include <machine/asmacros.h> | |
| bdc560a1 | 77 | #include <machine/segments.h> |
| 984263bc | 78 | |
| 984263bc | 79 | #include <machine/pmap.h> |
| a9295349 | 80 | #include <machine_base/apic/apicreg.h> |
| 984263bc | 81 | #include <machine/lock.h> |
| 984263bc MD |
82 | |
| 83 | #include "assym.s" | |
| 84 | ||
| a2a5ad0d MD |
85 | #if defined(SMP) |
| 86 | #define MPLOCKED lock ; | |
| 87 | #else | |
| 88 | #define MPLOCKED | |
| 89 | #endif | |
| 90 | ||
| 984263bc MD |
91 | .data |
| 92 | ||
| 2954c92f | 93 | .globl panic |
| cc9b6223 | 94 | .globl lwkt_switch_return |
| 984263bc MD |
95 | |
| 96 | #if defined(SWTCH_OPTIM_STATS) | |
| 2954c92f MD |
97 | .globl swtch_optim_stats, tlb_flush_count |
| 98 | swtch_optim_stats: .long 0 /* number of _swtch_optims */ | |
| 99 | tlb_flush_count: .long 0 | |
| 984263bc MD |
100 | #endif |
| 101 | ||
| 102 | .text | |
| 103 | ||
| 984263bc MD |
104 | |
| 105 | /* | |
| 8ad65e08 MD |
106 | * cpu_heavy_switch(next_thread) |
| 107 | * | |
| 108 | * Switch from the current thread to a new thread. This entry | |
| 109 | * is normally called via the thread->td_switch function, and will | |
| 110 | * only be called when the current thread is a heavy weight process. | |
| 111 | * | |
| d9eea1a5 MD |
112 | * Some instructions have been reordered to reduce pipeline stalls. |
| 113 | * | |
| 8ad65e08 | 114 | * YYY disable interrupts once giant is removed. |
| 984263bc | 115 | */ |
| 8ad65e08 | 116 | ENTRY(cpu_heavy_switch) |
| 8ad65e08 MD |
117 | /* |
| 118 | * Save general regs | |
| 119 | */ | |
| d9eea1a5 MD |
120 | movl PCPU(curthread),%ecx |
| 121 | movl (%esp),%eax /* (reorder optimization) */ | |
| 122 | movl TD_PCB(%ecx),%edx /* EDX = PCB */ | |
| 123 | movl %eax,PCB_EIP(%edx) /* return PC may be modified */ | |
| 984263bc MD |
124 | movl %ebx,PCB_EBX(%edx) |
| 125 | movl %esp,PCB_ESP(%edx) | |
| 126 | movl %ebp,PCB_EBP(%edx) | |
| 127 | movl %esi,PCB_ESI(%edx) | |
| 128 | movl %edi,PCB_EDI(%edx) | |
| b25897b2 | 129 | movl 4(%esp),%edi /* EDI = newthread */ |
| 984263bc | 130 | |
| b25897b2 MD |
131 | /* |
| 132 | * Clear the cpu bit in the pmap active mask. The restore | |
| 133 | * function will set the bit in the pmap active mask. | |
| 134 | * | |
| 135 | * Special case: when switching between threads sharing the | |
| 136 | * same vmspace if we avoid clearing the bit we do not have | |
| 137 | * to reload %cr3 (if we clear the bit we could race page | |
| 138 | * table ops done by other threads and would have to reload | |
| 139 | * %cr3, because those ops will not know to IPI us). | |
| 140 | */ | |
| 141 | movl %ecx,%ebx /* EBX = oldthread */ | |
| 142 | movl TD_LWP(%ecx),%ecx /* ECX = oldlwp */ | |
| 143 | movl TD_LWP(%edi),%esi /* ESI = newlwp */ | |
| 144 | movl LWP_VMSPACE(%ecx),%ecx /* ECX = oldvmspace */ | |
| 145 | testl %esi,%esi /* might not be a heavy */ | |
| 146 | jz 1f | |
| 147 | cmpl LWP_VMSPACE(%esi),%ecx /* same vmspace? */ | |
| 148 | je 2f | |
| 149 | 1: | |
| d9eea1a5 | 150 | movl PCPU(cpuid), %eax |
| d9eea1a5 | 151 | MPLOCKED btrl %eax, VM_PMAP+PM_ACTIVE(%ecx) |
| b25897b2 | 152 | 2: |
| 8ad65e08 MD |
153 | /* |
| 154 | * Push the LWKT switch restore function, which resumes a heavy | |
| 155 | * weight process. Note that the LWKT switcher is based on | |
| 156 | * TD_SP, while the heavy weight process switcher is based on | |
| d9eea1a5 MD |
157 | * PCB_ESP. TD_SP is usually two ints pushed relative to |
| 158 | * PCB_ESP. We push the flags for later restore by cpu_heavy_restore. | |
| 8ad65e08 | 159 | */ |
| d9eea1a5 | 160 | pushfl |
| 8ad65e08 | 161 | pushl $cpu_heavy_restore |
| d9eea1a5 | 162 | movl %esp,TD_SP(%ebx) |
| 8ad65e08 MD |
163 | |
| 164 | /* | |
| 165 | * Save debug regs if necessary | |
| 166 | */ | |
| 984263bc MD |
167 | movb PCB_FLAGS(%edx),%al |
| 168 | andb $PCB_DBREGS,%al | |
| 169 | jz 1f /* no, skip over */ | |
| 170 | movl %dr7,%eax /* yes, do the save */ | |
| 171 | movl %eax,PCB_DR7(%edx) | |
| 172 | andl $0x0000fc00, %eax /* disable all watchpoints */ | |
| 173 | movl %eax,%dr7 | |
| 174 | movl %dr6,%eax | |
| 175 | movl %eax,PCB_DR6(%edx) | |
| 176 | movl %dr3,%eax | |
| 177 | movl %eax,PCB_DR3(%edx) | |
| 178 | movl %dr2,%eax | |
| 179 | movl %eax,PCB_DR2(%edx) | |
| 180 | movl %dr1,%eax | |
| 181 | movl %eax,PCB_DR1(%edx) | |
| 182 | movl %dr0,%eax | |
| 183 | movl %eax,PCB_DR0(%edx) | |
| 184 | 1: | |
| 185 | ||
| 263541db | 186 | #if NNPX > 0 |
| 8ad65e08 | 187 | /* |
| a2a5ad0d MD |
188 | * Save the FP state if we have used the FP. Note that calling |
| 189 | * npxsave will NULL out PCPU(npxthread). | |
| 8ad65e08 | 190 | */ |
| d9eea1a5 | 191 | cmpl %ebx,PCPU(npxthread) |
| 984263bc | 192 | jne 1f |
| 65d6ce10 | 193 | pushl TD_SAVEFPU(%ebx) |
| 2954c92f | 194 | call npxsave /* do it in a big C function */ |
| d9eea1a5 | 195 | addl $4,%esp /* EAX, ECX, EDX trashed */ |
| 984263bc MD |
196 | 1: |
| 197 | #endif /* NNPX > 0 */ | |
| 198 | ||
| 84b592ba | 199 | /* |
| 8ad65e08 | 200 | * Switch to the next thread, which was passed as an argument |
| d9eea1a5 MD |
201 | * to cpu_heavy_switch(). Due to the eflags and switch-restore |
| 202 | * function we pushed, the argument is at 12(%esp). Set the current | |
| 203 | * thread, load the stack pointer, and 'ret' into the switch-restore | |
| 204 | * function. | |
| 205 | * | |
| 206 | * The switch restore function expects the new thread to be in %eax | |
| 207 | * and the old one to be in %ebx. | |
| 71ef2f5c MD |
208 | * |
| 209 | * There is a one-instruction window where curthread is the new | |
| 210 | * thread but %esp still points to the old thread's stack, but | |
| 211 | * we are protected by a critical section so it is ok. | |
| 84b592ba | 212 | */ |
| b25897b2 | 213 | movl %edi,%eax /* EAX = newtd, EBX = oldtd */ |
| 2954c92f | 214 | movl %eax,PCPU(curthread) |
| 8ad65e08 MD |
215 | movl TD_SP(%eax),%esp |
| 216 | ret | |
| 984263bc | 217 | |
| 8ad65e08 MD |
218 | /* |
| 219 | * cpu_exit_switch() | |
| 220 | * | |
| 221 | * The switch function is changed to this when a thread is going away | |
| 222 | * for good. We have to ensure that the MMU state is not cached, and | |
| 223 | * we don't bother saving the existing thread state before switching. | |
| ae8050a4 MD |
224 | * |
| 225 | * At this point we are in a critical section and this cpu owns the | |
| 226 | * thread's token, which serves as an interlock until the switchout is | |
| 227 | * complete. | |
| 8ad65e08 MD |
228 | */ |
| 229 | ENTRY(cpu_exit_switch) | |
| ae8050a4 MD |
230 | /* |
| 231 | * Get us out of the vmspace | |
| 232 | */ | |
| 2954c92f | 233 | movl IdlePTD,%ecx |
| 8ad65e08 MD |
234 | movl %cr3,%eax |
| 235 | cmpl %ecx,%eax | |
| 236 | je 1f | |
| 237 | movl %ecx,%cr3 | |
| 984263bc | 238 | 1: |
| d9eea1a5 | 239 | movl PCPU(curthread),%ebx |
| e3161323 MD |
240 | |
| 241 | /* | |
| 242 | * If this is a process/lwp, deactivate the pmap after we've | |
| 243 | * switched it out. | |
| 244 | */ | |
| 287ebb09 | 245 | movl TD_LWP(%ebx),%ecx |
| e3161323 MD |
246 | testl %ecx,%ecx |
| 247 | jz 2f | |
| 248 | movl PCPU(cpuid), %eax | |
| 287ebb09 | 249 | movl LWP_VMSPACE(%ecx), %ecx /* ECX = vmspace */ |
| e3161323 MD |
250 | MPLOCKED btrl %eax, VM_PMAP+PM_ACTIVE(%ecx) |
| 251 | 2: | |
| ae8050a4 | 252 | /* |
| d9eea1a5 MD |
253 | * Switch to the next thread. RET into the restore function, which |
| 254 | * expects the new thread in EAX and the old in EBX. | |
| 71ef2f5c MD |
255 | * |
| 256 | * There is a one-instruction window where curthread is the new | |
| 257 | * thread but %esp still points to the old thread's stack, but | |
| 258 | * we are protected by a critical section so it is ok. | |
| ae8050a4 | 259 | */ |
| 8ad65e08 | 260 | movl 4(%esp),%eax |
| 2954c92f | 261 | movl %eax,PCPU(curthread) |
| 8ad65e08 MD |
262 | movl TD_SP(%eax),%esp |
| 263 | ret | |
| 984263bc | 264 | |
| 8ad65e08 MD |
265 | /* |
| 266 | * cpu_heavy_restore() (current thread in %eax on entry) | |
| 267 | * | |
| 268 | * Restore the thread after an LWKT switch. This entry is normally | |
| 269 | * called via the LWKT switch restore function, which was pulled | |
| 270 | * off the thread stack and jumped to. | |
| 271 | * | |
| 272 | * This entry is only called if the thread was previously saved | |
| d9eea1a5 | 273 | * using cpu_heavy_switch() (the heavy weight process thread switcher), |
| cc9b6223 | 274 | * or when a new process is initially scheduled. |
| 8ad65e08 | 275 | * |
| 164b8401 | 276 | * NOTE: The lwp may be in any state, not necessarily LSRUN, because |
| b74c5f55 MD |
277 | * a preemption switch may interrupt the process and then return via |
| 278 | * cpu_heavy_restore. | |
| 279 | * | |
| 8ad65e08 MD |
280 | * YYY theoretically we do not have to restore everything here, a lot |
| 281 | * of this junk can wait until we return to usermode. But for now | |
| 282 | * we restore everything. | |
| 283 | * | |
| 96728c05 MD |
284 | * YYY the PCB crap is really crap, it makes startup a bitch because |
| 285 | * we can't switch away. | |
| 7d0bac62 MD |
286 | * |
| 287 | * YYY note: spl check is done in mi_switch when it splx()'s. | |
| 8ad65e08 | 288 | */ |
| 26a0694b | 289 | |
| 8ad65e08 | 290 | ENTRY(cpu_heavy_restore) |
| d9eea1a5 | 291 | popfl |
| 287ebb09 | 292 | movl TD_LWP(%eax),%ecx |
| 984263bc MD |
293 | |
| 294 | #if defined(SWTCH_OPTIM_STATS) | |
| 295 | incl _swtch_optim_stats | |
| 296 | #endif | |
| 8ad65e08 | 297 | /* |
| a2a5ad0d MD |
298 | * Tell the pmap that our cpu is using the VMSPACE now. We cannot |
| 299 | * safely test/reload %cr3 until after we have set the bit in the | |
| 300 | * pmap (remember, we do not hold the MP lock in the switch code). | |
| b25897b2 MD |
301 | * |
| 302 | * Also note that when switching between two lwps sharing the | |
| 303 | * same vmspace we have already avoided clearing the cpu bit | |
| 304 | * in pm_active. If we had cleared it other cpus would not know | |
| 305 | * to IPI us and we would have to unconditionally reload %cr3. | |
| 306 | * | |
| 307 | * Also note that if the pmap is undergoing an atomic inval/mod | |
| 308 | * that is unaware that our cpu has been added to it we have to | |
| 309 | * wait for it to complete before we can continue. | |
| 8ad65e08 | 310 | */ |
| 287ebb09 | 311 | movl LWP_VMSPACE(%ecx), %ecx /* ECX = vmspace */ |
| c2fb025d | 312 | #ifdef SMP |
| d8d8c8c5 MD |
313 | pushl %eax /* save curthread */ |
| 314 | 1: | |
| 315 | movl VM_PMAP+PM_ACTIVE(%ecx),%eax /* old value for cmpxchgl */ | |
| 316 | movl PCPU(cpumask), %esi | |
| 317 | orl %eax,%esi /* new value for cmpxchgl */ | |
| 318 | MPLOCKED cmpxchgl %esi,VM_PMAP+PM_ACTIVE(%ecx) | |
| 319 | jnz 1b | |
| 320 | ||
| 321 | /* | |
| 322 | * Check CPUMASK_BIT | |
| 323 | */ | |
| 324 | testl $CPUMASK_LOCK,%eax | |
| c2fb025d | 325 | jz 1f |
| d8d8c8c5 | 326 | pushl %ecx /* call(stack:vmspace) */ |
| c2fb025d MD |
327 | call pmap_interlock_wait |
| 328 | popl %ecx | |
| d8d8c8c5 MD |
329 | |
| 330 | /* | |
| 331 | * Needs unconditional load cr3 | |
| 332 | */ | |
| 333 | popl %eax /* EAX = curthread */ | |
| 334 | movl TD_PCB(%eax),%edx /* EDX = PCB */ | |
| 335 | movl PCB_CR3(%edx),%ecx | |
| 336 | jmp 2f | |
| c2fb025d | 337 | 1: |
| d8d8c8c5 MD |
338 | popl %eax |
| 339 | #else | |
| 340 | movl PCPU(cpumask), %esi | |
| 341 | orl %esi, VM_PMAP+PM_ACTIVE(%ecx) | |
| c2fb025d | 342 | #endif |
| a2a5ad0d MD |
343 | |
| 344 | /* | |
| 345 | * Restore the MMU address space. If it is the same as the last | |
| 346 | * thread we don't have to invalidate the tlb (i.e. reload cr3). | |
| 347 | * YYY which naturally also means that the PM_ACTIVE bit had better | |
| 348 | * already have been set before we set it above, check? YYY | |
| 349 | */ | |
| c2fb025d | 350 | movl TD_PCB(%eax),%edx /* EDX = PCB */ |
| d9eea1a5 MD |
351 | movl %cr3,%esi |
| 352 | movl PCB_CR3(%edx),%ecx | |
| 353 | cmpl %esi,%ecx | |
| 984263bc | 354 | je 4f |
| d8d8c8c5 | 355 | 2: |
| 984263bc MD |
356 | #if defined(SWTCH_OPTIM_STATS) |
| 357 | decl _swtch_optim_stats | |
| 358 | incl _tlb_flush_count | |
| 359 | #endif | |
| d9eea1a5 | 360 | movl %ecx,%cr3 |
| 984263bc | 361 | 4: |
| d8d8c8c5 | 362 | |
| 8ad65e08 | 363 | /* |
| cc9b6223 MD |
364 | * NOTE: %ebx is the previous thread and %eax is the new thread. |
| 365 | * %ebx is retained throughout so we can return it. | |
| 366 | * | |
| 367 | * lwkt_switch[_return] is responsible for handling TDF_RUNNING. | |
| d9eea1a5 | 368 | */ |
| d9eea1a5 MD |
369 | |
| 370 | /* | |
| 8ad65e08 MD |
371 | * Deal with the PCB extension, restore the private tss |
| 372 | */ | |
| a2a5ad0d | 373 | movl PCB_EXT(%edx),%edi /* check for a PCB extension */ |
| cc9b6223 | 374 | movl $1,%ecx /* maybe mark use of a private tss */ |
| a2a5ad0d MD |
375 | testl %edi,%edi |
| 376 | jnz 2f | |
| 984263bc | 377 | |
| b7c628e4 | 378 | /* |
| a2a5ad0d MD |
379 | * Going back to the common_tss. We may need to update TSS_ESP0 |
| 380 | * which sets the top of the supervisor stack when entering from | |
| 381 | * usermode. The PCB is at the top of the stack but we need another | |
| 382 | * 16 bytes to take vm86 into account. | |
| b7c628e4 | 383 | */ |
| cc9b6223 MD |
384 | leal -16(%edx),%ecx |
| 385 | movl %ecx, PCPU(common_tss) + TSS_ESP0 | |
| 984263bc | 386 | |
| a2a5ad0d MD |
387 | cmpl $0,PCPU(private_tss) /* don't have to reload if */ |
| 388 | je 3f /* already using the common TSS */ | |
| 389 | ||
| cc9b6223 | 390 | subl %ecx,%ecx /* unmark use of private tss */ |
| 17a9f566 MD |
391 | |
| 392 | /* | |
| a2a5ad0d | 393 | * Get the address of the common TSS descriptor for the ltr. |
| 17a9f566 MD |
394 | * There is no way to get the address of a segment-accessed variable |
| 395 | * so we store a self-referential pointer at the base of the per-cpu | |
| 396 | * data area and add the appropriate offset. | |
| 397 | */ | |
| 984263bc MD |
398 | movl $gd_common_tssd, %edi |
| 399 | addl %fs:0, %edi | |
| 17a9f566 | 400 | |
| 8ad65e08 MD |
401 | /* |
| 402 | * Move the correct TSS descriptor into the GDT slot, then reload | |
| a2a5ad0d | 403 | * ltr. |
| 8ad65e08 | 404 | */ |
| 984263bc | 405 | 2: |
| cc9b6223 MD |
406 | movl %ecx,PCPU(private_tss) /* mark/unmark private tss */ |
| 407 | movl PCPU(tss_gdt), %ecx /* entry in GDT */ | |
| 984263bc | 408 | movl 0(%edi), %eax |
| cc9b6223 | 409 | movl %eax, 0(%ecx) |
| 984263bc | 410 | movl 4(%edi), %eax |
| cc9b6223 | 411 | movl %eax, 4(%ecx) |
| 984263bc MD |
412 | movl $GPROC0_SEL*8, %esi /* GSEL(entry, SEL_KPL) */ |
| 413 | ltr %si | |
| 8ad65e08 | 414 | |
| 984263bc | 415 | 3: |
| 8ad65e08 | 416 | /* |
| cc9b6223 | 417 | * Restore general registers. %ebx is restored later. |
| 8ad65e08 | 418 | */ |
| 984263bc MD |
419 | movl PCB_ESP(%edx),%esp |
| 420 | movl PCB_EBP(%edx),%ebp | |
| 421 | movl PCB_ESI(%edx),%esi | |
| 422 | movl PCB_EDI(%edx),%edi | |
| 423 | movl PCB_EIP(%edx),%eax | |
| 424 | movl %eax,(%esp) | |
| 425 | ||
| 8ad65e08 | 426 | /* |
| 8ad65e08 MD |
427 | * Restore the user LDT if we have one |
| 428 | */ | |
| 984263bc MD |
429 | cmpl $0, PCB_USERLDT(%edx) |
| 430 | jnz 1f | |
| 2954c92f MD |
431 | movl _default_ldt,%eax |
| 432 | cmpl PCPU(currentldt),%eax | |
| 984263bc | 433 | je 2f |
| 2954c92f MD |
434 | lldt _default_ldt |
| 435 | movl %eax,PCPU(currentldt) | |
| 984263bc MD |
436 | jmp 2f |
| 437 | 1: pushl %edx | |
| 2954c92f | 438 | call set_user_ldt |
| 984263bc MD |
439 | popl %edx |
| 440 | 2: | |
| 8ad65e08 | 441 | /* |
| 806bf111 MD |
442 | * Restore the user TLS if we have one |
| 443 | */ | |
| 444 | pushl %edx | |
| 445 | call set_user_TLS | |
| 446 | popl %edx | |
| 984263bc | 447 | |
| 8ad65e08 MD |
448 | /* |
| 449 | * Restore the DEBUG register state if necessary. | |
| 450 | */ | |
| 984263bc MD |
451 | movb PCB_FLAGS(%edx),%al |
| 452 | andb $PCB_DBREGS,%al | |
| 453 | jz 1f /* no, skip over */ | |
| 454 | movl PCB_DR6(%edx),%eax /* yes, do the restore */ | |
| 455 | movl %eax,%dr6 | |
| 456 | movl PCB_DR3(%edx),%eax | |
| 457 | movl %eax,%dr3 | |
| 458 | movl PCB_DR2(%edx),%eax | |
| 459 | movl %eax,%dr2 | |
| 460 | movl PCB_DR1(%edx),%eax | |
| 461 | movl %eax,%dr1 | |
| 462 | movl PCB_DR0(%edx),%eax | |
| 463 | movl %eax,%dr0 | |
| 464 | movl %dr7,%eax /* load dr7 so as not to disturb */ | |
| 465 | andl $0x0000fc00,%eax /* reserved bits */ | |
| cc9b6223 MD |
466 | movl PCB_DR7(%edx),%ecx |
| 467 | andl $~0x0000fc00,%ecx | |
| 468 | orl %ecx,%eax | |
| 984263bc MD |
469 | movl %eax,%dr7 |
| 470 | 1: | |
| cc9b6223 MD |
471 | movl %ebx,%eax /* return previous thread */ |
| 472 | movl PCB_EBX(%edx),%ebx | |
| 984263bc MD |
473 | ret |
| 474 | ||
| 984263bc MD |
475 | /* |
| 476 | * savectx(pcb) | |
| 65d6ce10 | 477 | * |
| 984263bc MD |
478 | * Update pcb, saving current processor state. |
| 479 | */ | |
| 480 | ENTRY(savectx) | |
| 481 | /* fetch PCB */ | |
| 482 | movl 4(%esp),%ecx | |
| 483 | ||
| 484 | /* caller's return address - child won't execute this routine */ | |
| 485 | movl (%esp),%eax | |
| 486 | movl %eax,PCB_EIP(%ecx) | |
| 487 | ||
| 488 | movl %cr3,%eax | |
| 489 | movl %eax,PCB_CR3(%ecx) | |
| 490 | ||
| 491 | movl %ebx,PCB_EBX(%ecx) | |
| 492 | movl %esp,PCB_ESP(%ecx) | |
| 493 | movl %ebp,PCB_EBP(%ecx) | |
| 494 | movl %esi,PCB_ESI(%ecx) | |
| 495 | movl %edi,PCB_EDI(%ecx) | |
| 984263bc MD |
496 | |
| 497 | #if NNPX > 0 | |
| 498 | /* | |
| af0bff84 | 499 | * If npxthread == NULL, then the npx h/w state is irrelevant and the |
| 984263bc MD |
500 | * state had better already be in the pcb. This is true for forks |
| 501 | * but not for dumps (the old book-keeping with FP flags in the pcb | |
| 502 | * always lost for dumps because the dump pcb has 0 flags). | |
| 503 | * | |
| af0bff84 MD |
504 | * If npxthread != NULL, then we have to save the npx h/w state to |
| 505 | * npxthread's pcb and copy it to the requested pcb, or save to the | |
| 984263bc MD |
506 | * requested pcb and reload. Copying is easier because we would |
| 507 | * have to handle h/w bugs for reloading. We used to lose the | |
| 508 | * parent's npx state for forks by forgetting to reload. | |
| 509 | */ | |
| 2954c92f | 510 | movl PCPU(npxthread),%eax |
| 984263bc MD |
511 | testl %eax,%eax |
| 512 | je 1f | |
| 513 | ||
| a02705a9 MD |
514 | pushl %ecx /* target pcb */ |
| 515 | movl TD_SAVEFPU(%eax),%eax /* originating savefpu area */ | |
| 984263bc | 516 | pushl %eax |
| a02705a9 | 517 | |
| 984263bc | 518 | pushl %eax |
| 2954c92f | 519 | call npxsave |
| 984263bc | 520 | addl $4,%esp |
| a02705a9 | 521 | |
| 984263bc MD |
522 | popl %eax |
| 523 | popl %ecx | |
| 524 | ||
| 525 | pushl $PCB_SAVEFPU_SIZE | |
| 65d6ce10 | 526 | leal PCB_SAVEFPU(%ecx),%ecx |
| 984263bc MD |
527 | pushl %ecx |
| 528 | pushl %eax | |
| 2954c92f | 529 | call bcopy |
| 984263bc MD |
530 | addl $12,%esp |
| 531 | #endif /* NNPX > 0 */ | |
| 532 | ||
| 533 | 1: | |
| 534 | ret | |
| 8ad65e08 MD |
535 | |
| 536 | /* | |
| a2a5ad0d | 537 | * cpu_idle_restore() (current thread in %eax on entry) (one-time execution) |
| 8ad65e08 MD |
538 | * |
| 539 | * Don't bother setting up any regs other then %ebp so backtraces | |
| 540 | * don't die. This restore function is used to bootstrap into the | |
| 541 | * cpu_idle() LWKT only, after that cpu_lwkt_*() will be used for | |
| 542 | * switching. | |
| 72740893 | 543 | * |
| d9eea1a5 | 544 | * Clear TDF_RUNNING in old thread only after we've cleaned up %cr3. |
| cc9b6223 MD |
545 | * This only occurs during system boot so no special handling is |
| 546 | * required for migration. | |
| d9eea1a5 | 547 | * |
| 72740893 MD |
548 | * If we are an AP we have to call ap_init() before jumping to |
| 549 | * cpu_idle(). ap_init() will synchronize with the BP and finish | |
| 550 | * setting up various ncpu-dependant globaldata fields. This may | |
| 551 | * happen on UP as well as SMP if we happen to be simulating multiple | |
| 552 | * cpus. | |
| 8ad65e08 MD |
553 | */ |
| 554 | ENTRY(cpu_idle_restore) | |
| d9eea1a5 | 555 | /* cli */ |
| a2a5ad0d | 556 | movl IdlePTD,%ecx |
| 8ad65e08 MD |
557 | movl $0,%ebp |
| 558 | pushl $0 | |
| a2a5ad0d | 559 | movl %ecx,%cr3 |
| d9eea1a5 | 560 | andl $~TDF_RUNNING,TD_FLAGS(%ebx) |
| 121f93bc | 561 | orl $TDF_RUNNING,TD_FLAGS(%eax) /* manual, no switch_return */ |
| 72740893 MD |
562 | #ifdef SMP |
| 563 | cmpl $0,PCPU(cpuid) | |
| 564 | je 1f | |
| 565 | call ap_init | |
| 566 | 1: | |
| 567 | #endif | |
| d19f6edf MD |
568 | /* |
| 569 | * ap_init can decide to enable interrupts early, but otherwise, or if | |
| 570 | * we are UP, do it here. | |
| 571 | */ | |
| ef0fdad1 | 572 | sti |
| 8ad65e08 MD |
573 | jmp cpu_idle |
| 574 | ||
| 575 | /* | |
| a2a5ad0d | 576 | * cpu_kthread_restore() (current thread is %eax on entry) (one-time execution) |
| 0cfcada1 MD |
577 | * |
| 578 | * Don't bother setting up any regs other then %ebp so backtraces | |
| 579 | * don't die. This restore function is used to bootstrap into an | |
| 580 | * LWKT based kernel thread only. cpu_lwkt_switch() will be used | |
| 581 | * after this. | |
| 26a0694b MD |
582 | * |
| 583 | * Since all of our context is on the stack we are reentrant and | |
| 584 | * we can release our critical section and enable interrupts early. | |
| cc9b6223 MD |
585 | * |
| 586 | * Because this switch target does not 'return' to lwkt_switch() | |
| 587 | * we have to call lwkt_switch_return(otd) to clean up otd. | |
| 588 | * otd is in %ebx. | |
| 0cfcada1 MD |
589 | */ |
| 590 | ENTRY(cpu_kthread_restore) | |
| d9eea1a5 | 591 | sti |
| a2a5ad0d | 592 | movl IdlePTD,%ecx |
| cc9b6223 | 593 | movl TD_PCB(%eax),%esi |
| 0cfcada1 | 594 | movl $0,%ebp |
| a2a5ad0d | 595 | movl %ecx,%cr3 |
| cc9b6223 MD |
596 | |
| 597 | pushl %eax | |
| 598 | pushl %ebx /* argument to lwkt_switch_return */ | |
| 599 | call lwkt_switch_return | |
| 600 | addl $4,%esp | |
| 601 | popl %eax | |
| f9235b6d | 602 | decl TD_CRITCOUNT(%eax) |
| d9eea1a5 | 603 | popl %eax /* kthread exit function */ |
| cc9b6223 | 604 | pushl PCB_EBX(%esi) /* argument to ESI function */ |
| d9eea1a5 | 605 | pushl %eax /* set exit func as return address */ |
| cc9b6223 | 606 | movl PCB_ESI(%esi),%eax |
| 0cfcada1 MD |
607 | jmp *%eax |
| 608 | ||
| 609 | /* | |
| 8ad65e08 MD |
610 | * cpu_lwkt_switch() |
| 611 | * | |
| 612 | * Standard LWKT switching function. Only non-scratch registers are | |
| 613 | * saved and we don't bother with the MMU state or anything else. | |
| 26a0694b MD |
614 | * |
| 615 | * This function is always called while in a critical section. | |
| 616 | * | |
| 71ef2f5c MD |
617 | * There is a one-instruction window where curthread is the new |
| 618 | * thread but %esp still points to the old thread's stack, but | |
| 619 | * we are protected by a critical section so it is ok. | |
| 620 | * | |
| 8ad65e08 MD |
621 | * YYY BGL, SPL |
| 622 | */ | |
| 623 | ENTRY(cpu_lwkt_switch) | |
| 18bbe476 | 624 | pushl %ebp /* note: GDB hacked to locate ebp relative to td_sp */ |
| 8ad65e08 | 625 | pushl %ebx |
| 263541db | 626 | movl PCPU(curthread),%ebx |
| 8ad65e08 MD |
627 | pushl %esi |
| 628 | pushl %edi | |
| 629 | pushfl | |
| 263541db MD |
630 | /* warning: adjust movl into %eax below if you change the pushes */ |
| 631 | ||
| 632 | #if NNPX > 0 | |
| 633 | /* | |
| 634 | * Save the FP state if we have used the FP. Note that calling | |
| 635 | * npxsave will NULL out PCPU(npxthread). | |
| 636 | * | |
| 637 | * We have to deal with the FP state for LWKT threads in case they | |
| 638 | * happen to get preempted or block while doing an optimized | |
| 639 | * bzero/bcopy/memcpy. | |
| 640 | */ | |
| 641 | cmpl %ebx,PCPU(npxthread) | |
| 642 | jne 1f | |
| 65d6ce10 | 643 | pushl TD_SAVEFPU(%ebx) |
| 263541db MD |
644 | call npxsave /* do it in a big C function */ |
| 645 | addl $4,%esp /* EAX, ECX, EDX trashed */ | |
| 646 | 1: | |
| 647 | #endif /* NNPX > 0 */ | |
| 648 | ||
| 649 | movl 4+20(%esp),%eax /* switch to this thread */ | |
| 8ad65e08 | 650 | pushl $cpu_lwkt_restore |
| d9eea1a5 | 651 | movl %esp,TD_SP(%ebx) |
| 2954c92f | 652 | movl %eax,PCPU(curthread) |
| 8ad65e08 | 653 | movl TD_SP(%eax),%esp |
| d9eea1a5 MD |
654 | |
| 655 | /* | |
| 656 | * eax contains new thread, ebx contains old thread. | |
| 657 | */ | |
| 8ad65e08 MD |
658 | ret |
| 659 | ||
| 660 | /* | |
| 26a0694b | 661 | * cpu_lwkt_restore() (current thread in %eax on entry) |
| 8ad65e08 | 662 | * |
| 26a0694b MD |
663 | * Standard LWKT restore function. This function is always called |
| 664 | * while in a critical section. | |
| 665 | * | |
| 666 | * Warning: due to preemption the restore function can be used to | |
| 667 | * 'return' to the original thread. Interrupt disablement must be | |
| 668 | * protected through the switch so we cannot run splz here. | |
| a2a5ad0d MD |
669 | * |
| 670 | * YYY we theoretically do not need to load IdlePTD into cr3, but if | |
| 671 | * so we need a way to detect when the PTD we are using is being | |
| 672 | * deleted due to a process exiting. | |
| 8ad65e08 MD |
673 | */ |
| 674 | ENTRY(cpu_lwkt_restore) | |
| a2a5ad0d | 675 | movl IdlePTD,%ecx /* YYY borrow but beware desched/cpuchg/exit */ |
| d9eea1a5 MD |
676 | movl %cr3,%edx |
| 677 | cmpl %ecx,%edx | |
| a2a5ad0d MD |
678 | je 1f |
| 679 | movl %ecx,%cr3 | |
| 680 | 1: | |
| cc9b6223 MD |
681 | /* |
| 682 | * NOTE: %ebx is the previous thread and %eax is the new thread. | |
| 683 | * %ebx is retained throughout so we can return it. | |
| 684 | * | |
| 685 | * lwkt_switch[_return] is responsible for handling TDF_RUNNING. | |
| 686 | */ | |
| 687 | movl %ebx,%eax | |
| 8ad65e08 MD |
688 | popfl |
| 689 | popl %edi | |
| 690 | popl %esi | |
| 691 | popl %ebx | |
| 692 | popl %ebp | |
| 693 | ret | |
| 694 |