Annotation of src/sys/arch/i386/i386/locore.S, Revision 1.37
1.37 ! jmmv 1: /* $NetBSD: locore.S,v 1.36 2005/12/11 12:17:41 christos Exp $ */
1.1 fvdl 2:
3: /*-
1.32 mycroft 4: * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc.
1.1 fvdl 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Charles M. Hannum.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
38:
39: /*-
40: * Copyright (c) 1990 The Regents of the University of California.
41: * All rights reserved.
42: *
43: * This code is derived from software contributed to Berkeley by
44: * William Jolitz.
45: *
46: * Redistribution and use in source and binary forms, with or without
47: * modification, are permitted provided that the following conditions
48: * are met:
49: * 1. Redistributions of source code must retain the above copyright
50: * notice, this list of conditions and the following disclaimer.
51: * 2. Redistributions in binary form must reproduce the above copyright
52: * notice, this list of conditions and the following disclaimer in the
53: * documentation and/or other materials provided with the distribution.
1.12 agc 54: * 3. Neither the name of the University nor the names of its contributors
1.1 fvdl 55: * may be used to endorse or promote products derived from this software
56: * without specific prior written permission.
57: *
58: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68: * SUCH DAMAGE.
69: *
70: * @(#)locore.s 7.3 (Berkeley) 5/13/91
71: */
72:
1.18 christos 73: #include "opt_compat_netbsd.h"
74: #include "opt_compat_oldboot.h"
1.1 fvdl 75: #include "opt_cputype.h"
76: #include "opt_ddb.h"
77: #include "opt_ipkdb.h"
1.18 christos 78: #include "opt_lockdebug.h"
1.1 fvdl 79: #include "opt_multiprocessor.h"
80: #include "opt_realmem.h"
1.18 christos 81: #include "opt_user_ldt.h"
82: #include "opt_vm86.h"
1.1 fvdl 83:
84: #include "npx.h"
85: #include "assym.h"
86: #include "apm.h"
87: #include "lapic.h"
88: #include "ioapic.h"
1.8 fvdl 89: #include "ksyms.h"
1.1 fvdl 90:
91: #include <sys/errno.h>
92: #include <sys/syscall.h>
93:
94: #include <machine/cputypes.h>
95: #include <machine/segments.h>
96: #include <machine/specialreg.h>
97: #include <machine/trap.h>
98: #include <machine/bootinfo.h>
99:
100: #if NLAPIC > 0
101: #include <machine/i82489reg.h>
102: #endif
103:
1.37 ! jmmv 104: #include <machine/multiboot.h>
! 105:
1.1 fvdl 106: /* LINTSTUB: include <sys/types.h> */
107: /* LINTSTUB: include <machine/cpu.h> */
108: /* LINTSTUB: include <sys/systm.h> */
109:
110: #include <machine/asm.h>
111:
112: #if defined(MULTIPROCESSOR)
1.30 junyoung 113:
1.5 thorpej 114: #define SET_CURLWP(lwp,cpu) \
1.1 fvdl 115: movl CPUVAR(SELF),cpu ; \
1.5 thorpej 116: movl lwp,CPUVAR(CURLWP) ; \
117: movl cpu,L_CPU(lwp)
1.30 junyoung 118:
1.1 fvdl 119: #else
120:
1.5 thorpej 121: #define SET_CURLWP(lwp,tcpu) movl lwp,CPUVAR(CURLWP)
122: #define GET_CURLWP(reg) movl CPUVAR(CURLWP),reg
1.1 fvdl 123:
124: #endif
125:
126: #define SET_CURPCB(reg) movl reg,CPUVAR(CURPCB)
1.24 yamt 127:
1.1 fvdl 128: #define CLEAR_RESCHED(reg) movl reg,CPUVAR(RESCHED)
129:
130: /* XXX temporary kluge; these should not be here */
131: /* Get definitions for IOM_BEGIN, IOM_END, and IOM_SIZE */
132: #include <dev/isa/isareg.h>
133:
134:
135: /* Disallow old names for REALBASEMEM */
136: #ifdef BIOSBASEMEM
137: #error BIOSBASEMEM option deprecated; use REALBASEMEM only if memory size reported by latest boot block is incorrect
138: #endif
139:
140: /* Disallow old names for REALEXTMEM */
141: #ifdef EXTMEM_SIZE
142: #error EXTMEM_SIZE option deprecated; use REALEXTMEM only if memory size reported by latest boot block is incorrect
143: #endif
144: #ifdef BIOSEXTMEM
145: #error BIOSEXTMEM option deprecated; use REALEXTMEM only if memory size reported by latest boot block is incorrect
146: #endif
147:
148: #include <machine/frameasm.h>
149:
150:
151: #ifdef MULTIPROCESSOR
152: #include <machine/i82489reg.h>
153: #endif
1.30 junyoung 154:
1.1 fvdl 155: /*
156: * Initialization
157: */
158: .data
159:
160: .globl _C_LABEL(cpu)
161: .globl _C_LABEL(esym),_C_LABEL(boothowto)
162: .globl _C_LABEL(bootinfo),_C_LABEL(atdevbase)
163: #ifdef COMPAT_OLDBOOT
164: .globl _C_LABEL(bootdev)
165: #endif
1.31 junyoung 166: .globl _C_LABEL(proc0paddr),_C_LABEL(PDPpaddr)
1.1 fvdl 167: .globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem)
168: .globl _C_LABEL(gdt)
169: #ifdef I586_CPU
170: .globl _C_LABEL(idt)
171: #endif
1.30 junyoung 172: .globl _C_LABEL(lapic_tpr)
173:
1.1 fvdl 174: #if NLAPIC > 0
175: #ifdef __ELF__
1.7 thorpej 176: .align PAGE_SIZE
1.1 fvdl 177: #else
178: .align 12
179: #endif
180: .globl _C_LABEL(local_apic), _C_LABEL(lapic_id)
181: _C_LABEL(local_apic):
182: .space LAPIC_ID
1.30 junyoung 183: _C_LABEL(lapic_id):
1.1 fvdl 184: .long 0x00000000
185: .space LAPIC_TPRI-(LAPIC_ID+4)
1.30 junyoung 186: _C_LABEL(lapic_tpr):
1.1 fvdl 187: .space LAPIC_PPRI-LAPIC_TPRI
1.30 junyoung 188: _C_LABEL(lapic_ppr):
1.1 fvdl 189: .space LAPIC_ISR-LAPIC_PPRI
190: _C_LABEL(lapic_isr):
1.7 thorpej 191: .space PAGE_SIZE-LAPIC_ISR
1.1 fvdl 192: #else
1.30 junyoung 193: _C_LABEL(lapic_tpr):
1.1 fvdl 194: .long 0
195: #endif
1.30 junyoung 196:
1.1 fvdl 197:
198: _C_LABEL(cpu): .long 0 # are we 386, 386sx, or 486,
199: # or Pentium, or..
200: _C_LABEL(esym): .long 0 # ptr to end of syms
201: _C_LABEL(atdevbase): .long 0 # location of start of iomem in virtual
202: _C_LABEL(proc0paddr): .long 0
1.31 junyoung 203: _C_LABEL(PDPpaddr): .long 0 # paddr of PDP, for libkvm
1.1 fvdl 204: #ifndef REALBASEMEM
205: _C_LABEL(biosbasemem): .long 0 # base memory reported by BIOS
206: #else
207: _C_LABEL(biosbasemem): .long REALBASEMEM
208: #endif
209: #ifndef REALEXTMEM
210: _C_LABEL(biosextmem): .long 0 # extended memory reported by BIOS
211: #else
212: _C_LABEL(biosextmem): .long REALEXTMEM
213: #endif
1.30 junyoung 214:
1.1 fvdl 215: .space 512
216: tmpstk:
217:
218:
1.35 yamt 219: #define _RELOC(x) ((x) - KERNBASE)
1.1 fvdl 220: #define RELOC(x) _RELOC(_C_LABEL(x))
221:
222: .text
223: .globl _C_LABEL(kernel_text)
224: .set _C_LABEL(kernel_text),KERNTEXTOFF
225:
226: .globl start
227: start: movw $0x1234,0x472 # warm boot
228:
1.37 ! jmmv 229: #if defined(MULTIBOOT)
! 230: jmp 1f
! 231:
! 232: .align 4
! 233: .globl Multiboot_Header
! 234: _C_LABEL(Multiboot_Header):
! 235: #define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_WANT_MEMORY | \
! 236: MULTIBOOT_HEADER_HAS_ADDR)
! 237: .long MULTIBOOT_HEADER_MAGIC
! 238: .long MULTIBOOT_HEADER_FLAGS
! 239: .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
! 240: .long RELOC(Multiboot_Header)
! 241: .long RELOC(start)
! 242: .long RELOC(_edata)
! 243: .long RELOC(_end) + MULTIBOOT_SYMTAB_SPACE
! 244: .long RELOC(start)
! 245:
! 246: 1:
! 247: /* Check if we are being executed by a Multiboot-compliant boot
! 248: * loader. */
! 249: cmpl $MULTIBOOT_INFO_MAGIC,%eax
! 250: jne 1f
! 251:
! 252: /* Indeed, a multiboot-compliat boot loader executed us. We copy
! 253: * the received Multiboot information structure into kernel's data
! 254: * space to process it later -- after we are relocated. It will
! 255: * be safer to run complex C code than doing it at this point. */
! 256: pushl %ebx # Address of Multiboot information
! 257: call _C_LABEL(multiboot_pre_reloc)
! 258: addl $4,%esp
! 259: jmp 3f
! 260: #endif
! 261:
! 262: 1:
1.1 fvdl 263: /*
264: * Load parameters from stack
265: * (howto, [bootdev], bootinfo, esym, basemem, extmem).
266: */
267: movl 4(%esp),%eax
268: movl %eax,RELOC(boothowto)
269: #ifdef COMPAT_OLDBOOT
270: movl 8(%esp),%eax
271: movl %eax,RELOC(bootdev)
272: #endif
273: movl 12(%esp),%eax
274:
275: testl %eax, %eax
276: jz 1f
277: movl (%eax), %ebx /* number of entries */
278: movl $RELOC(bootinfo), %edi
279: movl %ebx, (%edi)
280: addl $4, %edi
281: 2:
282: testl %ebx, %ebx
283: jz 1f
284: addl $4, %eax
285: movl (%eax), %ecx /* address of entry */
286: pushl %eax
287: pushl (%ecx) /* len */
288: pushl %ecx
289: pushl %edi
290: addl (%ecx), %edi /* update dest pointer */
291: cmpl $_RELOC(_C_LABEL(bootinfo) + BOOTINFO_MAXSIZE), %edi
292: jg 2f
293: call _C_LABEL(memcpy)
294: addl $12, %esp
295: popl %eax
296: subl $1, %ebx
297: jmp 2b
298: 2: /* cleanup for overflow case */
299: addl $16, %esp
300: movl $RELOC(bootinfo), %edi
301: subl %ebx, (%edi) /* correct number of entries */
302: 1:
303:
304: movl 16(%esp),%eax
305: testl %eax,%eax
306: jz 1f
1.35 yamt 307: addl $KERNBASE,%eax
1.1 fvdl 308: 1: movl %eax,RELOC(esym)
309:
310: movl RELOC(biosextmem),%eax
311: testl %eax,%eax
312: jnz 1f
313: movl 20(%esp),%eax
314: movl %eax,RELOC(biosextmem)
315: 1:
316: movl RELOC(biosbasemem),%eax
317: testl %eax,%eax
318: jnz 1f
319: movl 24(%esp),%eax
320: movl %eax,RELOC(biosbasemem)
321: 1:
322:
1.37 ! jmmv 323: 3:
1.1 fvdl 324: /* First, reset the PSL. */
325: pushl $PSL_MBO
326: popfl
327:
328: /* Clear segment registers; always null in proc0. */
329: xorl %eax,%eax
330: movw %ax,%fs
331: movw %ax,%gs
332: decl %eax
333: movl %eax,RELOC(cpu_info_primary)+CPU_INFO_LEVEL
334:
335: /* Find out our CPU type. */
336:
337: try386: /* Try to toggle alignment check flag; does not exist on 386. */
338: pushfl
339: popl %eax
340: movl %eax,%ecx
341: orl $PSL_AC,%eax
342: pushl %eax
343: popfl
344: pushfl
345: popl %eax
346: xorl %ecx,%eax
347: andl $PSL_AC,%eax
348: pushl %ecx
349: popfl
350:
351: testl %eax,%eax
352: jnz try486
353:
354: /*
355: * Try the test of a NexGen CPU -- ZF will not change on a DIV
356: * instruction on a NexGen, it will on an i386. Documented in
357: * Nx586 Processor Recognition Application Note, NexGen, Inc.
358: */
359: movl $0x5555,%eax
360: xorl %edx,%edx
361: movl $2,%ecx
362: divl %ecx
363: jnz is386
364:
365: isnx586:
366: /*
367: * Don't try cpuid, as Nx586s reportedly don't support the
368: * PSL_ID bit.
369: */
370: movl $CPU_NX586,RELOC(cpu)
371: jmp 2f
372:
373: is386:
374: movl $CPU_386,RELOC(cpu)
375: jmp 2f
376:
377: try486: /* Try to toggle identification flag; does not exist on early 486s. */
378: pushfl
379: popl %eax
380: movl %eax,%ecx
381: xorl $PSL_ID,%eax
382: pushl %eax
383: popfl
384: pushfl
385: popl %eax
386: xorl %ecx,%eax
387: andl $PSL_ID,%eax
388: pushl %ecx
389: popfl
390:
391: testl %eax,%eax
392: jnz try586
393: is486: movl $CPU_486,RELOC(cpu)
394: /*
395: * Check Cyrix CPU
396: * Cyrix CPUs do not change the undefined flags following
397: * execution of the divide instruction which divides 5 by 2.
398: *
399: * Note: CPUID is enabled on M2, so it passes another way.
400: */
401: pushfl
402: movl $0x5555, %eax
403: xorl %edx, %edx
404: movl $2, %ecx
405: clc
406: divl %ecx
407: jnc trycyrix486
408: popfl
409: jmp 2f
410: trycyrix486:
411: movl $CPU_6x86,RELOC(cpu) # set CPU type
412: /*
413: * Check for Cyrix 486 CPU by seeing if the flags change during a
414: * divide. This is documented in the Cx486SLC/e SMM Programmer's
415: * Guide.
416: */
417: xorl %edx,%edx
418: cmpl %edx,%edx # set flags to known state
419: pushfl
420: popl %ecx # store flags in ecx
421: movl $-1,%eax
422: movl $4,%ebx
423: divl %ebx # do a long division
424: pushfl
425: popl %eax
426: xorl %ecx,%eax # are the flags different?
427: testl $0x8d5,%eax # only check C|PF|AF|Z|N|V
428: jne 2f # yes; must be Cyrix 6x86 CPU
429: movl $CPU_486DLC,RELOC(cpu) # set CPU type
430:
431: #ifndef CYRIX_CACHE_WORKS
432: /* Disable caching of the ISA hole only. */
433: invd
434: movb $CCR0,%al # Configuration Register index (CCR0)
435: outb %al,$0x22
436: inb $0x23,%al
437: orb $(CCR0_NC1|CCR0_BARB),%al
438: movb %al,%ah
439: movb $CCR0,%al
440: outb %al,$0x22
441: movb %ah,%al
442: outb %al,$0x23
443: invd
444: #else /* CYRIX_CACHE_WORKS */
445: /* Set cache parameters */
446: invd # Start with guaranteed clean cache
447: movb $CCR0,%al # Configuration Register index (CCR0)
448: outb %al,$0x22
449: inb $0x23,%al
450: andb $~CCR0_NC0,%al
451: #ifndef CYRIX_CACHE_REALLY_WORKS
452: orb $(CCR0_NC1|CCR0_BARB),%al
453: #else
454: orb $CCR0_NC1,%al
455: #endif
456: movb %al,%ah
457: movb $CCR0,%al
458: outb %al,$0x22
459: movb %ah,%al
460: outb %al,$0x23
461: /* clear non-cacheable region 1 */
462: movb $(NCR1+2),%al
463: outb %al,$0x22
464: movb $NCR_SIZE_0K,%al
465: outb %al,$0x23
466: /* clear non-cacheable region 2 */
467: movb $(NCR2+2),%al
468: outb %al,$0x22
469: movb $NCR_SIZE_0K,%al
470: outb %al,$0x23
471: /* clear non-cacheable region 3 */
472: movb $(NCR3+2),%al
473: outb %al,$0x22
474: movb $NCR_SIZE_0K,%al
475: outb %al,$0x23
476: /* clear non-cacheable region 4 */
477: movb $(NCR4+2),%al
478: outb %al,$0x22
479: movb $NCR_SIZE_0K,%al
480: outb %al,$0x23
481: /* enable caching in CR0 */
482: movl %cr0,%eax
483: andl $~(CR0_CD|CR0_NW),%eax
484: movl %eax,%cr0
485: invd
486: #endif /* CYRIX_CACHE_WORKS */
487:
488: jmp 2f
489:
490: try586: /* Use the `cpuid' instruction. */
491: xorl %eax,%eax
492: cpuid
493: movl %eax,RELOC(cpu_info_primary)+CPU_INFO_LEVEL
494:
495: 2:
496: /*
497: * Finished with old stack; load new %esp now instead of later so we
498: * can trace this code without having to worry about the trace trap
499: * clobbering the memory test or the zeroing of the bss+bootstrap page
500: * tables.
501: *
502: * The boot program should check:
503: * text+data <= &stack_variable - more_space_for_stack
504: * text+data+bss+pad+space_for_page_tables <= end_of_memory
505: * Oops, the gdt is in the carcass of the boot program so clearing
506: * the rest of memory is still not possible.
507: */
508: movl $_RELOC(tmpstk),%esp # bootstrap stack end location
509:
510: /*
511: * Virtual address space of kernel:
512: *
1.30 junyoung 513: * text | data | bss | [syms] | page dir | proc0 kstack
1.1 fvdl 514: * 0 1 2 3
515: */
1.7 thorpej 516: #define PROC0PDIR ((0) * PAGE_SIZE)
517: #define PROC0STACK ((1) * PAGE_SIZE)
518: #define SYSMAP ((1+UPAGES) * PAGE_SIZE)
519: #define TABLESIZE ((1+UPAGES) * PAGE_SIZE) /* + nkpde * PAGE_SIZE */
1.1 fvdl 520:
521: /* Find end of kernel image. */
522: movl $RELOC(end),%edi
1.8 fvdl 523: #if (NKSYMS || defined(DDB) || defined(LKM)) && !defined(SYMTAB_SPACE)
1.1 fvdl 524: /* Save the symbols (if loaded). */
525: movl RELOC(esym),%eax
526: testl %eax,%eax
527: jz 1f
1.35 yamt 528: subl $KERNBASE,%eax
1.1 fvdl 529: movl %eax,%edi
530: 1:
531: #endif
532:
533: /* Calculate where to start the bootstrap tables. */
534: movl %edi,%esi # edi = esym ? esym : end
535: addl $PGOFSET,%esi # page align up
536: andl $~PGOFSET,%esi
537:
538: /*
539: * Calculate the size of the kernel page table directory, and
1.29 mycroft 540: * how many entries it will have. Adjust nkpde to the actual
541: * kernel size automatically. Account for the bootstrap tables,
542: * round up, and add an extra 4MB.
1.1 fvdl 543: */
1.29 mycroft 544: leal TABLESIZE+NBPD+PDOFSET(%edi),%eax
545: shrl $PDSHIFT,%eax
1.1 fvdl 546: movl RELOC(nkpde),%ecx # get nkpde
1.29 mycroft 547: cmpl %ecx,%eax
548: jb 1f
549: movl %eax,%ecx
550: 1: cmpl $NKPTP_MIN,%ecx # larger than min?
1.1 fvdl 551: jge 1f
552: movl $NKPTP_MIN,%ecx # set at min
553: jmp 2f
554: 1: cmpl $NKPTP_MAX,%ecx # larger than max?
555: jle 2f
556: movl $NKPTP_MAX,%ecx
1.29 mycroft 557: 2: movl %ecx,RELOC(nkpde)
1.1 fvdl 558:
559: /* Clear memory for bootstrap tables. */
560: shll $PGSHIFT,%ecx
561: addl $TABLESIZE,%ecx
562: addl %esi,%ecx # end of tables
563: subl %edi,%ecx # size of tables
564: shrl $2,%ecx
565: xorl %eax,%eax
566: cld
567: rep
568: stosl
569:
570: /*
571: * fillkpt
572: * eax = pte (page frame | control | status)
573: * ebx = page table address
574: * ecx = number of pages to map
575: */
576: #define fillkpt \
577: 1: movl %eax,(%ebx) ; \
1.7 thorpej 578: addl $PAGE_SIZE,%eax ; /* increment physical address */ \
1.1 fvdl 579: addl $4,%ebx ; /* next pte */ \
580: loop 1b ;
581:
582: /*
583: * Build initial page tables.
584: */
585: /* Calculate end of text segment, rounded to a page. */
586: leal (RELOC(etext)+PGOFSET),%edx
587: andl $~PGOFSET,%edx
1.30 junyoung 588:
1.1 fvdl 589: /* Skip over the first 1MB. */
590: movl $_RELOC(KERNTEXTOFF),%eax
591: movl %eax,%ecx
592: shrl $PGSHIFT,%ecx
593: leal (SYSMAP)(%esi,%ecx,4),%ebx
594:
595: /* Map the kernel text read-only. */
596: movl %edx,%ecx
597: subl %eax,%ecx
598: shrl $PGSHIFT,%ecx
599: orl $(PG_V|PG_KR),%eax
600: fillkpt
601:
602: /* Map the data, BSS, and bootstrap tables read-write. */
603: leal (PG_V|PG_KW)(%edx),%eax
604: movl RELOC(nkpde),%ecx
605: shll $PGSHIFT,%ecx
606: addl $TABLESIZE,%ecx
607: addl %esi,%ecx # end of tables
608: subl %edx,%ecx # subtract end of text
609: shrl $PGSHIFT,%ecx
610: fillkpt
611:
612: /* Map ISA I/O memory. */
613: movl $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax # having these bits set
614: movl $(IOM_SIZE>>PGSHIFT),%ecx # for this many pte s,
615: fillkpt
616:
617: /*
618: * Construct a page table directory.
619: */
620: /* Install PDEs for temporary double map of kernel. */
621: movl RELOC(nkpde),%ecx # for this many pde s,
622: leal (PROC0PDIR+0*4)(%esi),%ebx # which is where temp maps!
623: leal (SYSMAP+PG_V|PG_KW)(%esi),%eax # pte for KPT in proc 0,
624: fillkpt
625:
626: /* Map kernel PDEs. */
627: movl RELOC(nkpde),%ecx # for this many pde s,
628: leal (PROC0PDIR+PDSLOT_KERN*4)(%esi),%ebx # kernel pde offset
629: leal (SYSMAP+PG_V|PG_KW)(%esi),%eax # pte for KPT in proc 0,
630: fillkpt
631:
632: /* Install a PDE recursively mapping page directory as a page table! */
633: leal (PROC0PDIR+PG_V|PG_KW)(%esi),%eax # pte for ptd
634: movl %eax,(PROC0PDIR+PDSLOT_PTE*4)(%esi) # recursive PD slot
635:
1.31 junyoung 636: /* Save phys. addr of PDP, for libkvm. */
637: movl %esi,RELOC(PDPpaddr)
1.1 fvdl 638:
639: /* Load base of page directory and enable mapping. */
640: movl %esi,%eax # phys address of ptd in proc 0
641: movl %eax,%cr3 # load ptd addr into mmu
642: movl %cr0,%eax # get control word
643: # enable paging & NPX emulation
644: orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_EM|CR0_MP),%eax
645: movl %eax,%cr0 # and let's page NOW!
646:
647: pushl $begin # jump to high mem
648: ret
649:
650: begin:
1.35 yamt 651: /* Now running relocated at KERNBASE. Remove double mapping. */
1.1 fvdl 652: movl _C_LABEL(nkpde),%ecx # for this many pde s,
653: leal (PROC0PDIR+0*4)(%esi),%ebx # which is where temp maps!
1.35 yamt 654: addl $(KERNBASE), %ebx # now use relocated address
1.1 fvdl 655: 1: movl $0,(%ebx)
656: addl $4,%ebx # next pde
657: loop 1b
658:
659: /* Relocate atdevbase. */
660: movl _C_LABEL(nkpde),%edx
661: shll $PGSHIFT,%edx
1.35 yamt 662: addl $(TABLESIZE+KERNBASE),%edx
1.1 fvdl 663: addl %esi,%edx
664: movl %edx,_C_LABEL(atdevbase)
665:
666: /* Set up bootstrap stack. */
1.35 yamt 667: leal (PROC0STACK+KERNBASE)(%esi),%eax
1.1 fvdl 668: movl %eax,_C_LABEL(proc0paddr)
669: leal (USPACE-FRAMESIZE)(%eax),%esp
670: movl %esi,PCB_CR3(%eax) # pcb->pcb_cr3
671: xorl %ebp,%ebp # mark end of frames
672:
1.37 ! jmmv 673: #if defined(MULTIBOOT)
! 674: /* It is now safe to parse the Multiboot information structure
! 675: * we saved before from C code. Note that we cannot delay its
! 676: * parsing any more because initgdt (called below) needs to make
! 677: * use of this information. */
! 678: call _C_LABEL(multiboot_post_reloc)
! 679: #endif
! 680:
1.1 fvdl 681: subl $NGDT*8, %esp # space for temporary gdt
682: pushl %esp
683: call _C_LABEL(initgdt)
684: addl $4,%esp
1.30 junyoung 685:
1.1 fvdl 686: movl _C_LABEL(nkpde),%eax
687: shll $PGSHIFT,%eax
688: addl $TABLESIZE,%eax
689: addl %esi,%eax # skip past stack and page tables
690:
691: pushl %eax
692: call _C_LABEL(init386) # wire 386 chip for unix operation
693: addl $4+NGDT*8,%esp # pop temporary gdt
694:
695: #ifdef SAFARI_FIFO_HACK
696: movb $5,%al
697: movw $0x37b,%dx
698: outb %al,%dx
699: movw $0x37f,%dx
700: inb %dx,%al
701: movb %al,%cl
702:
703: orb $1,%cl
704:
705: movb $5,%al
706: movw $0x37b,%dx
707: outb %al,%dx
708: movw $0x37f,%dx
709: movb %cl,%al
710: outb %al,%dx
711: #endif /* SAFARI_FIFO_HACK */
712:
713: call _C_LABEL(main)
714:
715: /*
716: * void proc_trampoline(void);
717: * This is a trampoline function pushed onto the stack of a newly created
718: * process in order to do some additional setup. The trampoline is entered by
719: * cpu_switch()ing to the process, so we abuse the callee-saved registers used
720: * by cpu_switch() to store the information about the stub to call.
721: * NOTE: This function does not have a normal calling sequence!
722: */
723: /* LINTSTUB: Func: void proc_trampoline(void) */
724: NENTRY(proc_trampoline)
725: #ifdef MULTIPROCESSOR
726: call _C_LABEL(proc_trampoline_mp)
727: #endif
728: movl $IPL_NONE,CPUVAR(ILEVEL)
729: pushl %ebx
730: call *%esi
731: addl $4,%esp
1.24 yamt 732: DO_DEFERRED_SWITCH(%eax)
1.1 fvdl 733: INTRFASTEXIT
734: /* NOTREACHED */
735:
736: /*****************************************************************************/
1.16 christos 737: #ifdef COMPAT_16
1.1 fvdl 738: /*
739: * Signal trampoline; copied to top of user stack.
740: */
741: /* LINTSTUB: Var: char sigcode[1], esigcode[1]; */
742: NENTRY(sigcode)
743: /*
744: * Handler has returned here as if we called it. The sigcontext
745: * is on the stack after the 3 args "we" pushed.
746: */
747: leal 12(%esp),%eax # get pointer to sigcontext
748: movl %eax,4(%esp) # put it in the argument slot
749: # fake return address already there
1.17 christos 750: movl $SYS_compat_16___sigreturn14,%eax
1.1 fvdl 751: int $0x80 # enter kernel with args on stack
752: movl $SYS_exit,%eax
753: int $0x80 # exit if sigreturn fails
754: .globl _C_LABEL(esigcode)
755: _C_LABEL(esigcode):
1.16 christos 756: #endif
1.1 fvdl 757:
758: /*****************************************************************************/
759:
760: /*
761: * The following is i386-specific nonsense.
762: */
763:
764: /*
765: * void lgdt(struct region_descriptor *rdp);
766: * Load a new GDT pointer (and do any necessary cleanup).
767: * XXX It's somewhat questionable whether reloading all the segment registers
768: * is necessary, since the actual descriptor data is not changed except by
769: * process creation and exit, both of which clean up via task switches. OTOH,
770: * this only happens at run time when the GDT is resized.
771: */
772: /* LINTSTUB: Func: void lgdt(struct region_descriptor *rdp) */
773: NENTRY(lgdt)
774: /* Reload the descriptor table. */
775: movl 4(%esp),%eax
776: lgdt (%eax)
777: /* Flush the prefetch queue. */
778: jmp 1f
779: nop
780: 1: /* Reload "stale" selectors. */
781: movl $GSEL(GDATA_SEL, SEL_KPL),%eax
782: movw %ax,%ds
783: movw %ax,%es
784: movw %ax,%gs
785: movw %ax,%ss
786: movl $GSEL(GCPU_SEL, SEL_KPL),%eax
787: movw %ax,%fs
788: /* Reload code selector by doing intersegment return. */
789: popl %eax
790: pushl $GSEL(GCODE_SEL, SEL_KPL)
791: pushl %eax
792: lret
793:
794: /*****************************************************************************/
795:
796: /*
797: * These functions are primarily used by DDB.
798: */
799:
800: /* LINTSTUB: Func: int setjmp (label_t *l) */
801: ENTRY(setjmp)
802: movl 4(%esp),%eax
803: movl %ebx,(%eax) # save ebx
804: movl %esp,4(%eax) # save esp
805: movl %ebp,8(%eax) # save ebp
806: movl %esi,12(%eax) # save esi
807: movl %edi,16(%eax) # save edi
808: movl (%esp),%edx # get rta
809: movl %edx,20(%eax) # save eip
810: xorl %eax,%eax # return (0);
811: ret
812:
813: /* LINTSTUB: Func: void longjmp (label_t *l) */
814: ENTRY(longjmp)
815: movl 4(%esp),%eax
816: movl (%eax),%ebx # restore ebx
817: movl 4(%eax),%esp # restore esp
818: movl 8(%eax),%ebp # restore ebp
819: movl 12(%eax),%esi # restore esi
820: movl 16(%eax),%edi # restore edi
821: movl 20(%eax),%edx # get rta
822: movl %edx,(%esp) # put in return frame
823: xorl %eax,%eax # return (1);
824: incl %eax
825: ret
826:
827: /*****************************************************************************/
828:
829: .globl _C_LABEL(sched_whichqs),_C_LABEL(sched_qs)
830: .globl _C_LABEL(uvmexp),_C_LABEL(panic)
831:
832: #ifdef DIAGNOSTIC
833: NENTRY(switch_error)
834: pushl $1f
835: call _C_LABEL(panic)
836: /* NOTREACHED */
837: 1: .asciz "cpu_switch"
838: #endif /* DIAGNOSTIC */
839:
840: /*
1.5 thorpej 841: * void cpu_switch(struct lwp *)
1.1 fvdl 842: * Find a runnable process and switch to it. Wait if necessary. If the new
843: * process is the same as the old one, we short-circuit the context save and
844: * restore.
1.30 junyoung 845: *
1.1 fvdl 846: * Note that the stack frame layout is known to "struct switchframe"
1.30 junyoung 847: * in <machine/frame.h> and to the code in cpu_fork() which initializes
1.5 thorpej 848: * it for a new lwp.
1.1 fvdl 849: */
850: ENTRY(cpu_switch)
851: pushl %ebx
852: pushl %esi
853: pushl %edi
854:
855: #ifdef DEBUG
856: cmpl $IPL_SCHED,CPUVAR(ILEVEL)
857: jae 1f
1.5 thorpej 858: pushl $2f
1.1 fvdl 859: call _C_LABEL(panic)
860: /* NOTREACHED */
1.5 thorpej 861: 2: .asciz "not splsched() in cpu_switch!"
1.30 junyoung 862: 1:
1.1 fvdl 863: #endif /* DEBUG */
1.30 junyoung 864:
1.5 thorpej 865: movl 16(%esp),%esi # current
1.1 fvdl 866:
867: /*
1.5 thorpej 868: * Clear curlwp so that we don't accumulate system time while idle.
869: * This also insures that schedcpu() will move the old lwp to
1.1 fvdl 870: * the correct queue if it happens to get called from the spllower()
871: * below and changes the priority. (See corresponding comment in
872: * userret()).
873: */
1.5 thorpej 874: movl $0,CPUVAR(CURLWP)
1.1 fvdl 875: /*
1.5 thorpej 876: * First phase: find new lwp.
1.1 fvdl 877: *
878: * Registers:
879: * %eax - queue head, scratch, then zero
880: * %ebx - queue number
881: * %ecx - cached value of whichqs
1.5 thorpej 882: * %edx - next lwp in queue
883: * %esi - old lwp
884: * %edi - new lwp
1.1 fvdl 885: */
886:
1.5 thorpej 887: /* Look for new lwp. */
1.1 fvdl 888: cli # splhigh doesn't do a cli
889: movl _C_LABEL(sched_whichqs),%ecx
890: bsfl %ecx,%ebx # find a full q
891: jnz switch_dequeue
892:
893: /*
894: * idling: save old context.
895: *
896: * Registers:
897: * %eax, %ecx - scratch
1.5 thorpej 898: * %esi - old lwp, then old pcb
1.1 fvdl 899: * %edi - idle pcb
900: */
901:
902: pushl %esi
1.24 yamt 903: call _C_LABEL(pmap_deactivate2) # pmap_deactivate(oldproc)
1.1 fvdl 904: addl $4,%esp
905:
1.5 thorpej 906: movl L_ADDR(%esi),%esi
1.1 fvdl 907:
908: /* Save stack pointers. */
909: movl %esp,PCB_ESP(%esi)
910: movl %ebp,PCB_EBP(%esi)
911:
912: /* Find idle PCB for this CPU */
913: #ifndef MULTIPROCESSOR
1.5 thorpej 914: movl $_C_LABEL(lwp0),%ebx
915: movl L_ADDR(%ebx),%edi
916: movl L_MD_TSS_SEL(%ebx),%edx
1.1 fvdl 917: #else
918: movl CPUVAR(IDLE_PCB),%edi
919: movl CPUVAR(IDLE_TSS_SEL),%edx
920: #endif
1.5 thorpej 921: movl $0,CPUVAR(CURLWP) /* In case we fault... */
1.1 fvdl 922:
923: /* Restore the idle context (avoid interrupts) */
924: cli
925:
926: /* Restore stack pointers. */
927: movl PCB_ESP(%edi),%esp
928: movl PCB_EBP(%edi),%ebp
929:
930: /* Switch TSS. Reset "task busy" flag before loading. */
1.26 yamt 931: movl %cr3,%eax
932: movl %eax,PCB_CR3(%edi)
1.1 fvdl 933: #ifdef MULTIPROCESSOR
934: movl CPUVAR(GDT),%eax
935: #else
936: movl _C_LABEL(gdt),%eax
937: #endif
938: andl $~0x0200,4-SEL_KPL(%eax,%edx,1)
939: ltr %dx
940:
941: /* We're always in the kernel, so we don't need the LDT. */
942:
943: /* Restore cr0 (including FPU state). */
944: movl PCB_CR0(%edi),%ecx
945: movl %ecx,%cr0
946:
947: /* Record new pcb. */
948: SET_CURPCB(%edi)
949:
950: xorl %esi,%esi
951: sti
1.30 junyoung 952: idle_unlock:
953: #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
1.1 fvdl 954: call _C_LABEL(sched_unlock_idle)
955: #endif
956: /* Interrupts are okay again. */
1.2 fvdl 957: pushl $IPL_NONE # spl0()
1.1 fvdl 958: call _C_LABEL(Xspllower) # process pending interrupts
1.2 fvdl 959: addl $4,%esp
1.1 fvdl 960: jmp idle_start
1.30 junyoung 961: idle_zero:
1.1 fvdl 962: sti
963: call _C_LABEL(uvm_pageidlezero)
964: cli
965: cmpl $0,_C_LABEL(sched_whichqs)
966: jnz idle_exit
967: idle_loop:
968: /* Try to zero some pages. */
969: movl _C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO,%ecx
970: testl %ecx,%ecx
971: jnz idle_zero
972: sti
973: hlt
974: NENTRY(mpidle)
1.30 junyoung 975: idle_start:
1.1 fvdl 976: cli
977: cmpl $0,_C_LABEL(sched_whichqs)
978: jz idle_loop
1.30 junyoung 979: idle_exit:
1.1 fvdl 980: movl $IPL_HIGH,CPUVAR(ILEVEL) # splhigh
1.14 fvdl 981: sti
1.30 junyoung 982: #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
1.1 fvdl 983: call _C_LABEL(sched_lock_idle)
984: #endif
985: movl _C_LABEL(sched_whichqs),%ecx
986: bsfl %ecx,%ebx
987: jz idle_unlock
988:
1.30 junyoung 989: switch_dequeue:
990: /*
1.1 fvdl 991: * we're running at splhigh(), but it's otherwise okay to take
1.30 junyoung 992: * interrupts here.
1.1 fvdl 993: */
994: sti
995: leal _C_LABEL(sched_qs)(,%ebx,8),%eax # select q
996:
1.5 thorpej 997: movl L_FORW(%eax),%edi # unlink from front of process q
1.1 fvdl 998: #ifdef DIAGNOSTIC
999: cmpl %edi,%eax # linked to self (i.e. nothing queued)?
1000: je _C_LABEL(switch_error) # not possible
1001: #endif /* DIAGNOSTIC */
1.5 thorpej 1002: movl L_FORW(%edi),%edx
1003: movl %edx,L_FORW(%eax)
1004: movl %eax,L_BACK(%edx)
1.1 fvdl 1005:
1006: cmpl %edx,%eax # q empty?
1007: jne 3f
1008:
1009: btrl %ebx,%ecx # yes, clear to indicate empty
1010: movl %ecx,_C_LABEL(sched_whichqs) # update q status
1011:
1012: 3: /* We just did it. */
1013: xorl %eax,%eax
1014: CLEAR_RESCHED(%eax)
1015:
1.5 thorpej 1016: switch_resume:
1.1 fvdl 1017: #ifdef DIAGNOSTIC
1.5 thorpej 1018: cmpl %eax,L_WCHAN(%edi) # Waiting for something?
1.1 fvdl 1019: jne _C_LABEL(switch_error) # Yes; shouldn't be queued.
1.5 thorpej 1020: cmpb $LSRUN,L_STAT(%edi) # In run state?
1.1 fvdl 1021: jne _C_LABEL(switch_error) # No; shouldn't be queued.
1022: #endif /* DIAGNOSTIC */
1023:
1.5 thorpej 1024: /* Isolate lwp. XXX Is this necessary? */
1025: movl %eax,L_BACK(%edi)
1.1 fvdl 1026:
1.5 thorpej 1027: /* Record new lwp. */
1028: movb $LSONPROC,L_STAT(%edi) # l->l_stat = LSONPROC
1029: SET_CURLWP(%edi,%ecx)
1.1 fvdl 1030:
1.5 thorpej 1031: /* Skip context switch if same lwp. */
1.10 fvdl 1032: xorl %ebx,%ebx
1.1 fvdl 1033: cmpl %edi,%esi
1034: je switch_return
1035:
1.5 thorpej 1036: /* If old lwp exited, don't bother. */
1.1 fvdl 1037: testl %esi,%esi
1038: jz switch_exited
1039:
1040: /*
1041: * Second phase: save old context.
1042: *
1043: * Registers:
1044: * %eax, %ecx - scratch
1.5 thorpej 1045: * %esi - old lwp, then old pcb
1046: * %edi - new lwp
1.1 fvdl 1047: */
1048:
1049: pushl %esi
1.24 yamt 1050: call _C_LABEL(pmap_deactivate2) # pmap_deactivate(oldproc)
1.1 fvdl 1051: addl $4,%esp
1052:
1.5 thorpej 1053: movl L_ADDR(%esi),%esi
1.1 fvdl 1054:
1055: /* Save stack pointers. */
1056: movl %esp,PCB_ESP(%esi)
1057: movl %ebp,PCB_EBP(%esi)
1058:
1059: switch_exited:
1060: /*
1061: * Third phase: restore saved context.
1062: *
1063: * Registers:
1064: * %eax, %ebx, %ecx, %edx - scratch
1065: * %esi - new pcb
1.5 thorpej 1066: * %edi - new lwp
1.1 fvdl 1067: */
1068:
1069: /* No interrupts while loading new state. */
1070: cli
1.5 thorpej 1071: movl L_ADDR(%edi),%esi
1.1 fvdl 1072:
1073: /* Restore stack pointers. */
1074: movl PCB_ESP(%esi),%esp
1075: movl PCB_EBP(%esi),%ebp
1076:
1077: #if 0
1078: /* Don't bother with the rest if switching to a system process. */
1.5 thorpej 1079: testl $P_SYSTEM,L_FLAG(%edi); XXX NJWLWP lwp's don't have P_SYSTEM!
1.1 fvdl 1080: jnz switch_restored
1081: #endif
1082:
1.26 yamt 1083: /* Switch TSS. Reset "task busy" flag before loading. */
1084: movl %cr3,%eax
1085: movl %eax,PCB_CR3(%esi) /* XXX should be done by pmap_activate? */
1.1 fvdl 1086: #ifdef MULTIPROCESSOR
1087: movl CPUVAR(GDT),%eax
1.30 junyoung 1088: #else
1.1 fvdl 1089: /* Load TSS info. */
1090: movl _C_LABEL(gdt),%eax
1091: #endif
1.5 thorpej 1092: movl L_MD_TSS_SEL(%edi),%edx
1.1 fvdl 1093:
1094: andl $~0x0200,4(%eax,%edx, 1)
1095: ltr %dx
1096:
1097: pushl %edi
1098: call _C_LABEL(pmap_activate) # pmap_activate(p)
1099: addl $4,%esp
1100:
1101: #if 0
1102: switch_restored:
1103: #endif
1104: /* Restore cr0 (including FPU state). */
1105: movl PCB_CR0(%esi),%ecx
1106: #ifdef MULTIPROCESSOR
1.30 junyoung 1107: /*
1.22 wiz 1108: * If our floating point registers are on a different CPU,
1.1 fvdl 1109: * clear CR0_TS so we'll trap rather than reuse bogus state.
1110: */
1111: movl PCB_FPCPU(%esi),%ebx
1112: cmpl CPUVAR(SELF),%ebx
1113: jz 1f
1114: orl $CR0_TS,%ecx
1.30 junyoung 1115: 1:
1116: #endif
1.1 fvdl 1117: movl %ecx,%cr0
1118:
1119: /* Record new pcb. */
1120: SET_CURPCB(%esi)
1121:
1122: /* Interrupts are okay again. */
1123: sti
1124:
1125: /*
1126: * Check for restartable atomic sequences (RAS)
1127: */
1.5 thorpej 1128: movl CPUVAR(CURLWP),%edi
1129: movl L_PROC(%edi),%esi
1.20 dsl 1130: cmpl $0,P_RASLIST(%esi)
1131: jne 2f
1.1 fvdl 1132: 1:
1.10 fvdl 1133: movl $1,%ebx
1.1 fvdl 1134:
1135: switch_return:
1.30 junyoung 1136: #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
1.1 fvdl 1137: call _C_LABEL(sched_unlock_idle)
1138: #endif
1.28 yamt 1139: cmpl $0,CPUVAR(IPENDING)
1140: jz 3f
1.2 fvdl 1141: pushl $IPL_NONE # spl0()
1.1 fvdl 1142: call _C_LABEL(Xspllower) # process pending interrupts
1.2 fvdl 1143: addl $4,%esp
1.28 yamt 1144: 3:
1.1 fvdl 1145: movl $IPL_HIGH,CPUVAR(ILEVEL) # splhigh()
1.9 fvdl 1146:
1147: movl %ebx,%eax
1.30 junyoung 1148:
1.1 fvdl 1149: popl %edi
1150: popl %esi
1151: popl %ebx
1152: ret
1.20 dsl 1153:
1154: 2: # check RAS list
1155: movl L_MD_REGS(%edi),%ebx
1156: movl TF_EIP(%ebx),%eax
1157: pushl %eax
1158: pushl %esi
1159: call _C_LABEL(ras_lookup)
1160: addl $8,%esp
1161: cmpl $-1,%eax
1162: je 1b
1163: movl %eax,TF_EIP(%ebx)
1164: jmp 1b
1.1 fvdl 1165:
1166: /*
1.5 thorpej 1167: * void cpu_switchto(struct lwp *current, struct lwp *next)
1168: * Switch to the specified next LWP.
1169: */
1170: ENTRY(cpu_switchto)
1171: pushl %ebx
1172: pushl %esi
1173: pushl %edi
1174:
1175: #ifdef DEBUG
1176: cmpl $IPL_SCHED,CPUVAR(ILEVEL)
1177: jae 1f
1178: pushl $2f
1179: call _C_LABEL(panic)
1180: /* NOTREACHED */
1181: 2: .asciz "not splsched() in cpu_switchto!"
1182: 1:
1183: #endif /* DEBUG */
1184:
1185: movl 16(%esp),%esi # current
1186: movl 20(%esp),%edi # next
1187:
1188: /*
1189: * Clear curlwp so that we don't accumulate system time while idle.
1190: * This also insures that schedcpu() will move the old process to
1191: * the correct queue if it happens to get called from the spllower()
1192: * below and changes the priority. (See corresponding comment in
1193: * usrret()).
1194: *
1195: * XXX Is this necessary? We know we won't go idle.
1196: */
1197: movl $0,CPUVAR(CURLWP)
1198:
1199: /*
1200: * We're running at splhigh(), but it's otherwise okay to take
1201: * interrupts here.
1202: */
1203: sti
1204:
1205: /* Jump into the middle of cpu_switch */
1206: xorl %eax,%eax
1207: jmp switch_resume
1208:
1209: /*
1.21 jdolecek 1210: * void cpu_exit(struct lwp *l)
1.30 junyoung 1211: * Switch to the appropriate idle context (lwp0's if uniprocessor; the CPU's
1212: * if multiprocessor) and deallocate the address space and kernel stack for p.
1.1 fvdl 1213: * Then jump into cpu_switch(), as if we were in the idle proc all along.
1214: */
1215: #ifndef MULTIPROCESSOR
1.5 thorpej 1216: .globl _C_LABEL(lwp0)
1.1 fvdl 1217: #endif
1.21 jdolecek 1218: /* LINTSTUB: Func: void cpu_exit(struct lwp *l) */
1219: ENTRY(cpu_exit)
1.1 fvdl 1220: movl 4(%esp),%edi # old process
1221: #ifndef MULTIPROCESSOR
1.5 thorpej 1222: movl $_C_LABEL(lwp0),%ebx
1223: movl L_ADDR(%ebx),%esi
1224: movl L_MD_TSS_SEL(%ebx),%edx
1.1 fvdl 1225: #else
1226: movl CPUVAR(IDLE_PCB),%esi
1227: movl CPUVAR(IDLE_TSS_SEL),%edx
1228: #endif
1229: /* In case we fault... */
1.5 thorpej 1230: movl $0,CPUVAR(CURLWP)
1.1 fvdl 1231:
1232: /* Restore the idle context. */
1233: cli
1234:
1235: /* Restore stack pointers. */
1236: movl PCB_ESP(%esi),%esp
1237: movl PCB_EBP(%esi),%ebp
1238:
1.26 yamt 1239: /* Switch TSS. Reset "task busy" flag before loading. */
1240: movl %cr3,%eax
1241: movl %eax,PCB_CR3(%esi)
1.1 fvdl 1242: #ifdef MULTIPROCESSOR
1243: movl CPUVAR(GDT),%eax
1.30 junyoung 1244: #else
1.1 fvdl 1245: /* Load TSS info. */
1246: movl _C_LABEL(gdt),%eax
1247: #endif
1248:
1249: andl $~0x0200,4-SEL_KPL(%eax,%edx,1)
1250: ltr %dx
1251:
1252: /* We're always in the kernel, so we don't need the LDT. */
1253:
1254: /* Restore cr0 (including FPU state). */
1255: movl PCB_CR0(%esi),%ecx
1256: movl %ecx,%cr0
1257:
1258: /* Record new pcb. */
1259: SET_CURPCB(%esi)
1260:
1261: /* Interrupts are okay again. */
1262: sti
1263:
1264: /*
1.21 jdolecek 1265: * Schedule the dead LWP's stack to be freed.
1.1 fvdl 1266: */
1.21 jdolecek 1267: pushl %edi
1268: call _C_LABEL(lwp_exit2)
1.1 fvdl 1269: addl $4,%esp
1270:
1271: /* Jump into cpu_switch() with the right state. */
1272: xorl %esi,%esi
1.5 thorpej 1273: movl %esi,CPUVAR(CURLWP)
1.1 fvdl 1274: jmp idle_start
1275:
1276: /*
1277: * void savectx(struct pcb *pcb);
1278: * Update pcb, saving current processor state.
1279: */
1280: /* LINTSTUB: Func: void savectx(struct pcb *pcb) */
1281: ENTRY(savectx)
1282: movl 4(%esp),%edx # edx = p->p_addr
1.30 junyoung 1283:
1.1 fvdl 1284: /* Save stack pointers. */
1285: movl %esp,PCB_ESP(%edx)
1286: movl %ebp,PCB_EBP(%edx)
1287:
1288: ret
1289:
1290: /*
1291: * Old call gate entry for syscall
1292: */
1293: /* LINTSTUB: Var: char Xosyscall[1]; */
1294: IDTVEC(osyscall)
1295: /* Set eflags in trap frame. */
1296: pushfl
1297: popl 8(%esp)
1298: pushl $7 # size of instruction for restart
1299: jmp syscall1
1300:
1301: /*
1302: * Trap gate entry for syscall
1303: */
1304: /* LINTSTUB: Var: char Xsyscall[1]; */
1305: IDTVEC(syscall)
1306: pushl $2 # size of instruction for restart
1307: syscall1:
1308: pushl $T_ASTFLT # trap # for doing ASTs
1309: INTRENTRY
1310:
1311: #ifdef DIAGNOSTIC
1.24 yamt 1312: cmpl $0, CPUVAR(WANT_PMAPLOAD)
1313: jz 1f
1314: pushl $6f
1315: call _C_LABEL(printf)
1316: addl $4, %esp
1317: 1:
1.1 fvdl 1318: movl CPUVAR(ILEVEL),%ebx
1319: testl %ebx,%ebx
1320: jz 1f
1321: pushl $5f
1322: call _C_LABEL(printf)
1323: addl $4,%esp
1324: #ifdef DDB
1325: int $3
1326: #endif
1.30 junyoung 1327: 1:
1.1 fvdl 1328: #endif /* DIAGNOSTIC */
1.5 thorpej 1329: movl CPUVAR(CURLWP),%edx
1330: movl %esp,L_MD_REGS(%edx) # save pointer to frame
1331: movl L_PROC(%edx),%edx
1.15 fvdl 1332: pushl %esp
1.1 fvdl 1333: call *P_MD_SYSCALL(%edx) # get pointer to syscall() function
1.15 fvdl 1334: addl $4,%esp
1.27 yamt 1335: .Lsyscall_checkast:
1.24 yamt 1336: /* Check for ASTs on exit to user mode. */
1.1 fvdl 1337: cli
1.5 thorpej 1338: CHECK_ASTPENDING(%eax)
1.1 fvdl 1339: je 1f
1340: /* Always returning to user mode here. */
1.5 thorpej 1341: CLEAR_ASTPENDING(%eax)
1.1 fvdl 1342: sti
1343: /* Pushed T_ASTFLT into tf_trapno on entry. */
1.15 fvdl 1344: pushl %esp
1.1 fvdl 1345: call _C_LABEL(trap)
1.15 fvdl 1346: addl $4,%esp
1.27 yamt 1347: jmp .Lsyscall_checkast /* re-check ASTs */
1.24 yamt 1348: 1: CHECK_DEFERRED_SWITCH(%eax)
1349: jnz 9f
1.1 fvdl 1350: #ifndef DIAGNOSTIC
1.24 yamt 1351: INTRFASTEXIT
1.1 fvdl 1352: #else /* DIAGNOSTIC */
1.24 yamt 1353: cmpl $IPL_NONE,CPUVAR(ILEVEL)
1.1 fvdl 1354: jne 3f
1355: INTRFASTEXIT
1356: 3: sti
1357: pushl $4f
1358: call _C_LABEL(printf)
1359: addl $4,%esp
1360: #ifdef DDB
1361: int $3
1362: #endif /* DDB */
1363: movl $IPL_NONE,CPUVAR(ILEVEL)
1364: jmp 2b
1365: 4: .asciz "WARNING: SPL NOT LOWERED ON SYSCALL EXIT\n"
1.30 junyoung 1366: 5: .asciz "WARNING: SPL NOT ZERO ON SYSCALL ENTRY\n"
1367: 6: .asciz "WARNING: WANT PMAPLOAD ON SYSCALL ENTRY\n"
1.1 fvdl 1368: #endif /* DIAGNOSTIC */
1.24 yamt 1369: 9: sti
1370: call _C_LABEL(pmap_load)
1.27 yamt 1371: jmp .Lsyscall_checkast /* re-check ASTs */
1.1 fvdl 1372:
1373: #if NNPX > 0
1374: /*
1375: * Special interrupt handlers. Someday intr0-intr15 will be used to count
1376: * interrupts. We'll still need a special exception 16 handler. The busy
1377: * latch stuff in probintr() can be moved to npxprobe().
1378: */
1379:
1380: /* LINTSTUB: Func: void probeintr(void) */
1381: NENTRY(probeintr)
1382: ss
1383: incl _C_LABEL(npx_intrs_while_probing)
1384: pushl %eax
1385: movb $0x20,%al # EOI (asm in strings loses cpp features)
1386: outb %al,$0xa0 # IO_ICU2
1387: outb %al,$0x20 # IO_ICU1
1388: movb $0,%al
1389: outb %al,$0xf0 # clear BUSY# latch
1390: popl %eax
1391: iret
1392:
1393: /* LINTSTUB: Func: void probetrap(void) */
1394: NENTRY(probetrap)
1395: ss
1396: incl _C_LABEL(npx_traps_while_probing)
1397: fnclex
1398: iret
1399:
1400: /* LINTSTUB: Func: int npx586bug1(int a, int b) */
1401: NENTRY(npx586bug1)
1402: fildl 4(%esp) # x
1403: fildl 8(%esp) # y
1404: fld %st(1)
1405: fdiv %st(1),%st # x/y
1406: fmulp %st,%st(1) # (x/y)*y
1407: fsubrp %st,%st(1) # x-(x/y)*y
1408: pushl $0
1409: fistpl (%esp)
1410: popl %eax
1411: ret
1412: #endif /* NNPX > 0 */
CVSweb <webmaster@jp.NetBSD.org>