9597 Want hypervisor API for FPU management
[unleashed.git] / usr / src / uts / i86pc / ml / cpr_wakecode.s
blob6955d5893edf856fe123cff41f686230c7b3bd1e
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/asm_linkage.h>
26 #include <sys/asm_misc.h>
27 #include <sys/regset.h>
28 #include <sys/privregs.h>
29 #include <sys/x86_archext.h>
30 #include <sys/cpr_wakecode.h>
32 #if !defined(__lint)
33 #include <sys/segments.h>
34 #include "assym.h"
35 #endif
37 #ifdef DEBUG
38 #define LED 1
39 #define SERIAL 1
40 #endif /* DEBUG */
42 #ifdef DEBUG
43 #define COM1 0x3f8
44 #define COM2 0x2f8
45 #define WC_COM COM2 /* either COM1 or COM2 */
46 #define WC_LED 0x80 /* diagnostic led port ON motherboard */
49 * defined as offsets from the data register
51 #define DLL 0 /* divisor latch (lsb) */
52 #define DLH 1 /* divisor latch (msb) */
53 #define LCR 3 /* line control register */
54 #define MCR 4 /* modem control register */
57 #define DLAB 0x80 /* divisor latch access bit */
58 #define B9600L 0X0c /* lsb bit pattern for 9600 baud */
59 #define B9600H 0X0 /* hsb bit pattern for 9600 baud */
60 #define DTR 0x01 /* Data Terminal Ready */
61 #define RTS 0x02 /* Request To Send */
62 #define STOP1 0x00 /* 1 stop bit */
63 #define BITS8 0x03 /* 8 bits per char */
65 #endif /* DEBUG */
68 * This file contains the low level routines involved in getting
69 * into and out of ACPI S3, including those needed for restarting
70 * the non-boot cpus.
72 * Our assumptions:
74 * Our actions:
78 #if defined(lint) || defined(__lint)
80 /*ARGSUSED*/
81 int
82 wc_save_context(wc_cpu_t *pcpu)
83 { return 0; }
85 #else /* lint */
87 #if defined(__amd64)
89 ENTRY_NP(wc_save_context)
91 movq (%rsp), %rdx / return address
92 movq %rdx, WC_RETADDR(%rdi)
93 pushq %rbp
94 movq %rsp,%rbp
96 movq %rdi, WC_VIRTADDR(%rdi)
97 movq %rdi, WC_RDI(%rdi)
99 movq %rdx, WC_RDX(%rdi)
101 / stash everything else we need
102 sgdt WC_GDT(%rdi)
103 sidt WC_IDT(%rdi)
104 sldt WC_LDT(%rdi)
105 str WC_TR(%rdi)
107 movq %cr0, %rdx
108 movq %rdx, WC_CR0(%rdi)
109 movq %cr3, %rdx
110 movq %rdx, WC_CR3(%rdi)
111 movq %cr4, %rdx
112 movq %rdx, WC_CR4(%rdi)
113 movq %cr8, %rdx
114 movq %rdx, WC_CR8(%rdi)
116 movq %r8, WC_R8(%rdi)
117 movq %r9, WC_R9(%rdi)
118 movq %r10, WC_R10(%rdi)
119 movq %r11, WC_R11(%rdi)
120 movq %r12, WC_R12(%rdi)
121 movq %r13, WC_R13(%rdi)
122 movq %r14, WC_R14(%rdi)
123 movq %r15, WC_R15(%rdi)
124 movq %rax, WC_RAX(%rdi)
125 movq %rbp, WC_RBP(%rdi)
126 movq %rbx, WC_RBX(%rdi)
127 movq %rcx, WC_RCX(%rdi)
128 movq %rsi, WC_RSI(%rdi)
129 movq %rsp, WC_RSP(%rdi)
131 movw %ss, WC_SS(%rdi)
132 movw %cs, WC_CS(%rdi)
133 movw %ds, WC_DS(%rdi)
134 movw %es, WC_ES(%rdi)
136 movq $0, %rcx / save %fs register
137 movw %fs, %cx
138 movq %rcx, WC_FS(%rdi)
140 movl $MSR_AMD_FSBASE, %ecx
141 rdmsr
142 movl %eax, WC_FSBASE(%rdi)
143 movl %edx, WC_FSBASE+4(%rdi)
145 movq $0, %rcx / save %gs register
146 movw %gs, %cx
147 movq %rcx, WC_GS(%rdi)
149 movl $MSR_AMD_GSBASE, %ecx / save gsbase msr
150 rdmsr
151 movl %eax, WC_GSBASE(%rdi)
152 movl %edx, WC_GSBASE+4(%rdi)
154 movl $MSR_AMD_KGSBASE, %ecx / save kgsbase msr
155 rdmsr
156 movl %eax, WC_KGSBASE(%rdi)
157 movl %edx, WC_KGSBASE+4(%rdi)
159 movq %gs:CPU_ID, %rax / save current cpu id
160 movq %rax, WC_CPU_ID(%rdi)
162 pushfq
163 popq WC_EFLAGS(%rdi)
165 wbinvd / flush the cache
166 mfence
168 movq $1, %rax / at suspend return 1
170 leave
174 SET_SIZE(wc_save_context)
176 #elif defined(__i386)
178 ENTRY_NP(wc_save_context)
180 movl 4(%esp), %eax / wc_cpu_t *
181 movl %eax, WC_VIRTADDR(%eax)
183 movl (%esp), %edx / return address
184 movl %edx, WC_RETADDR(%eax)
186 str WC_TR(%eax) / stash everything else we need
187 sgdt WC_GDT(%eax)
188 sldt WC_LDT(%eax)
189 sidt WC_IDT(%eax)
191 movl %cr0, %edx
192 movl %edx, WC_CR0(%eax)
193 movl %cr3, %edx
194 movl %edx, WC_CR3(%eax)
195 movl %cr4, %edx
196 movl %edx, WC_CR4(%eax)
198 movl %ebx, WC_EBX(%eax)
199 movl %edi, WC_EDI(%eax)
200 movl %esi, WC_ESI(%eax)
201 movl %ebp, WC_EBP(%eax)
202 movl %esp, WC_ESP(%eax)
204 movw %ss, WC_SS(%eax)
205 movw %cs, WC_CS(%eax)
206 movw %ds, WC_DS(%eax)
207 movw %es, WC_ES(%eax)
208 movw %fs, WC_FS(%eax)
209 movw %gs, WC_GS(%eax)
211 pushfl
212 popl WC_EFLAGS(%eax)
214 pushl %gs:CPU_ID / save current cpu id
215 popl WC_CPU_ID(%eax)
217 wbinvd / flush the cache
218 mfence
220 movl $1, %eax / at suspend return 1
223 SET_SIZE(wc_save_context)
225 #endif /* __amd64 */
227 #endif /* lint */
231 * Our assumptions:
232 * - We are running in real mode.
233 * - Interrupts are disabled.
235 * Our actions:
236 * - We start using our GDT by loading correct values in the
237 * selector registers (cs=KCS_SEL, ds=es=ss=KDS_SEL, fs=KFS_SEL,
238 * gs=KGS_SEL).
239 * - We change over to using our IDT.
240 * - We load the default LDT into the hardware LDT register.
241 * - We load the default TSS into the hardware task register.
242 * - We restore registers
243 * - We return to original caller (a la setjmp)
246 #if defined(lint) || defined(__lint)
248 void
249 wc_rm_start(void)
252 void
253 wc_rm_end(void)
256 #else /* lint */
258 #if defined(__amd64)
260 ENTRY_NP(wc_rm_start)
263 * For the Sun Studio 10 assembler we needed to do a .code32 and
264 * mentally invert the meaning of the addr16 and data16 prefixes to
265 * get 32-bit access when generating code to be executed in 16-bit
266 * mode (sigh...)
268 * This code, despite always being built with GNU as, has inherited
269 * the conceptual damage.
272 .code32
275 movw %cs, %ax
276 movw %ax, %ds / establish ds ...
277 movw %ax, %ss / ... and ss:esp
278 D16 movl $WC_STKSTART, %esp
279 / using the following value blows up machines! - DO NOT USE
280 / D16 movl 0xffc, %esp
283 #if LED
284 D16 movl $WC_LED, %edx
285 D16 movb $0xd1, %al
286 outb (%dx)
287 #endif
289 #if SERIAL
290 D16 movl $WC_COM, %edx
291 D16 movb $0x61, %al
292 outb (%dx)
293 #endif
295 D16 call cominit
298 * Enable protected-mode, write protect, and alignment mask
299 * %cr0 has already been initialsed to zero
301 movl %cr0, %eax
302 D16 orl $_CONST(CR0_PE|CR0_WP|CR0_AM), %eax
303 movl %eax, %cr0
306 * Do a jmp immediately after writing to cr0 when enabling protected
307 * mode to clear the real mode prefetch queue (per Intel's docs)
309 jmp pestart
310 pestart:
312 #if LED
313 D16 movl $WC_LED, %edx
314 D16 movb $0xd2, %al
315 outb (%dx)
316 #endif
318 #if SERIAL
319 D16 movl $WC_COM, %edx
320 D16 movb $0x62, %al
321 outb (%dx)
322 #endif
325 * 16-bit protected mode is now active, so prepare to turn on long
326 * mode
329 #if LED
330 D16 movl $WC_LED, %edx
331 D16 movb $0xd3, %al
332 outb (%dx)
333 #endif
335 #if SERIAL
336 D16 movl $WC_COM, %edx
337 D16 movb $0x63, %al
338 outb (%dx)
339 #endif
342 * Add any initial cr4 bits
344 movl %cr4, %eax
345 A16 D16 orl CR4OFF, %eax
348 * Enable PAE mode (CR4.PAE)
350 D16 orl $CR4_PAE, %eax
351 movl %eax, %cr4
353 #if LED
354 D16 movl $WC_LED, %edx
355 D16 movb $0xd4, %al
356 outb (%dx)
357 #endif
359 #if SERIAL
360 D16 movl $WC_COM, %edx
361 D16 movb $0x64, %al
362 outb (%dx)
363 #endif
366 * Point cr3 to the 64-bit long mode page tables.
368 * Note that these MUST exist in 32-bit space, as we don't have
369 * a way to load %cr3 with a 64-bit base address for the page tables
370 * until the CPU is actually executing in 64-bit long mode.
372 A16 D16 movl CR3OFF, %eax
373 movl %eax, %cr3
376 * Set long mode enable in EFER (EFER.LME = 1)
378 D16 movl $MSR_AMD_EFER, %ecx
379 rdmsr
381 D16 orl $AMD_EFER_LME, %eax
382 wrmsr
384 #if LED
385 D16 movl $WC_LED, %edx
386 D16 movb $0xd5, %al
387 outb (%dx)
388 #endif
390 #if SERIAL
391 D16 movl $WC_COM, %edx
392 D16 movb $0x65, %al
393 outb (%dx)
394 #endif
397 * Finally, turn on paging (CR0.PG = 1) to activate long mode.
399 movl %cr0, %eax
400 D16 orl $CR0_PG, %eax
401 movl %eax, %cr0
404 * The instruction after enabling paging in CR0 MUST be a branch.
406 jmp long_mode_active
408 long_mode_active:
410 #if LED
411 D16 movl $WC_LED, %edx
412 D16 movb $0xd6, %al
413 outb (%dx)
414 #endif
416 #if SERIAL
417 D16 movl $WC_COM, %edx
418 D16 movb $0x66, %al
419 outb (%dx)
420 #endif
423 * Long mode is now active but since we're still running with the
424 * original 16-bit CS we're actually in 16-bit compatability mode.
426 * We have to load an intermediate GDT and IDT here that we know are
427 * in 32-bit space before we can use the kernel's GDT and IDT, which
428 * may be in the 64-bit address space, and since we're in compatability
429 * mode, we only have access to 16 and 32-bit instructions at the
430 * moment.
432 A16 D16 lgdt TEMPGDTOFF /* load temporary GDT */
433 A16 D16 lidt TEMPIDTOFF /* load temporary IDT */
437 * Do a far transfer to 64-bit mode. Set the CS selector to a 64-bit
438 * long mode selector (CS.L=1) in the temporary 32-bit GDT and jump
439 * to the real mode platter address of wc_long_mode_64 as until the
440 * 64-bit CS is in place we don't have access to 64-bit instructions
441 * and thus can't reference a 64-bit %rip.
444 #if LED
445 D16 movl $WC_LED, %edx
446 D16 movb $0xd7, %al
447 outb (%dx)
448 #endif
450 #if SERIAL
451 D16 movl $WC_COM, %edx
452 D16 movb $0x67, %al
453 outb (%dx)
454 #endif
456 D16 pushl $TEMP_CS64_SEL
457 A16 D16 pushl LM64OFF
459 D16 lret
463 * Support routine to re-initialize VGA subsystem
465 vgainit:
466 D16 ret
469 * Support routine to re-initialize keyboard (which is USB - help!)
471 kbdinit:
472 D16 ret
475 * Support routine to re-initialize COM ports to something sane
477 cominit:
478 / init COM1 & COM2
480 #if DEBUG
482 * on debug kernels we need to initialize COM1 & COM2 here, so that
483 * we can get debug output before the asy driver has resumed
486 / select COM1
487 D16 movl $_CONST(COM1+LCR), %edx
488 D16 movb $DLAB, %al / divisor latch
489 outb (%dx)
491 D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
492 D16 movb $B9600L, %al / divisor latch
493 outb (%dx)
495 D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
496 D16 movb $B9600H, %al / divisor latch
497 outb (%dx)
499 D16 movl $_CONST(COM1+LCR), %edx / select COM1
500 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
501 outb (%dx)
503 D16 movl $_CONST(COM1+MCR), %edx / select COM1
504 D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
505 outb (%dx)
507 / select COM2
508 D16 movl $_CONST(COM2+LCR), %edx
509 D16 movb $DLAB, %al / divisor latch
510 outb (%dx)
512 D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
513 D16 movb $B9600L, %al / divisor latch
514 outb (%dx)
516 D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
517 D16 movb $B9600H, %al / divisor latch
518 outb (%dx)
520 D16 movl $_CONST(COM2+LCR), %edx / select COM1
521 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
522 outb (%dx)
524 D16 movl $_CONST(COM2+MCR), %edx / select COM1
525 D16 movb $_CONST(RTS|DTR), %al / data term ready & req to send
526 outb (%dx)
527 #endif /* DEBUG */
529 D16 ret
531 .code64
533 .globl wc_long_mode_64
534 wc_long_mode_64:
536 #if LED
537 movw $WC_LED, %dx
538 movb $0xd8, %al
539 outb (%dx)
540 #endif
542 #if SERIAL
543 movw $WC_COM, %dx
544 movb $0x68, %al
545 outb (%dx)
546 #endif
549 * We are now running in long mode with a 64-bit CS (EFER.LMA=1,
550 * CS.L=1) so we now have access to 64-bit instructions.
552 * First, set the 64-bit GDT base.
554 .globl rm_platter_pa
555 movl rm_platter_pa, %eax
557 lgdtq GDTROFF(%rax) /* load 64-bit GDT */
560 * Save the CPU number in %r11; get the value here since it's saved in
561 * the real mode platter.
563 / JAN
564 / the following is wrong! need to figure out MP systems
565 / movl CPUNOFF(%rax), %r11d
568 * Add rm_platter_pa to %rsp to point it to the same location as seen
569 * from 64-bit mode.
571 addq %rax, %rsp
574 * Now do an lretq to load CS with the appropriate selector for the
575 * kernel's 64-bit GDT and to start executing 64-bit setup code at the
576 * virtual address where boot originally loaded this code rather than
577 * the copy in the real mode platter's rm_code array as we've been
578 * doing so far.
581 #if LED
582 movw $WC_LED, %dx
583 movb $0xd9, %al
584 outb (%dx)
585 #endif
587 / JAN this should produce 'i' but we get 'g' instead ???
588 #if SERIAL
589 movw $WC_COM, %dx
590 movb $0x69, %al
591 outb (%dx)
592 #endif
594 pushq $KCS_SEL
595 pushq $kernel_wc_code
596 lretq
598 .globl kernel_wc_code
599 kernel_wc_code:
601 #if LED
602 movw $WC_LED, %dx
603 movb $0xda, %al
604 outb (%dx)
605 #endif
607 / JAN this should produce 'j' but we get 'g' instead ???
608 #if SERIAL
609 movw $WC_COM, %dx
610 movb $0x6a, %al
611 outb (%dx)
612 #endif
615 * Complete the balance of the setup we need to before executing
616 * 64-bit kernel code (namely init rsp, TSS, LGDT, FS and GS).
618 .globl rm_platter_va
619 movq rm_platter_va, %rbx
620 addq $WC_CPU, %rbx
622 #if LED
623 movw $WC_LED, %dx
624 movb $0xdb, %al
625 outb (%dx)
626 #endif
628 #if SERIAL
629 movw $WC_COM, %dx
630 movw $0x6b, %ax
631 outb (%dx)
632 #endif
635 * restore the rest of the registers
638 lidtq WC_IDT(%rbx)
640 #if LED
641 movw $WC_LED, %dx
642 movb $0xdc, %al
643 outb (%dx)
644 #endif
646 #if SERIAL
647 movw $WC_COM, %dx
648 movw $0x6c, %ax
649 outb (%dx)
650 #endif
653 * restore the rest of the registers
656 movw $KDS_SEL, %ax
657 movw %ax, %ds
658 movw %ax, %es
659 movw %ax, %ss
662 * Before proceeding, enable usage of the page table NX bit if
663 * that's how the page tables are set up.
665 bt $X86FSET_NX, x86_featureset(%rip)
666 jnc 1f
667 movl $MSR_AMD_EFER, %ecx
668 rdmsr
669 orl $AMD_EFER_NXE, %eax
670 wrmsr
673 movq WC_CR4(%rbx), %rax / restore full cr4 (with Global Enable)
674 movq %rax, %cr4
676 lldt WC_LDT(%rbx)
677 movzwq WC_TR(%rbx), %rax / clear TSS busy bit
678 addq WC_GDT+2(%rbx), %rax
679 andl $0xfffffdff, 4(%rax)
680 movq 4(%rax), %rcx
681 ltr WC_TR(%rbx)
683 #if LED
684 movw $WC_LED, %dx
685 movb $0xdd, %al
686 outb (%dx)
687 #endif
689 #if SERIAL
690 movw $WC_COM, %dx
691 movw $0x6d, %ax
692 outb (%dx)
693 #endif
695 / restore %fsbase %gsbase %kgbase registers using wrmsr instruction
697 movq WC_FS(%rbx), %rcx / restore fs register
698 movw %cx, %fs
700 movl $MSR_AMD_FSBASE, %ecx
701 movl WC_FSBASE(%rbx), %eax
702 movl WC_FSBASE+4(%rbx), %edx
703 wrmsr
705 movq WC_GS(%rbx), %rcx / restore gs register
706 movw %cx, %gs
708 movl $MSR_AMD_GSBASE, %ecx / restore gsbase msr
709 movl WC_GSBASE(%rbx), %eax
710 movl WC_GSBASE+4(%rbx), %edx
711 wrmsr
713 movl $MSR_AMD_KGSBASE, %ecx / restore kgsbase msr
714 movl WC_KGSBASE(%rbx), %eax
715 movl WC_KGSBASE+4(%rbx), %edx
716 wrmsr
718 movq WC_CR0(%rbx), %rdx
719 movq %rdx, %cr0
720 movq WC_CR3(%rbx), %rdx
721 movq %rdx, %cr3
722 movq WC_CR8(%rbx), %rdx
723 movq %rdx, %cr8
725 #if LED
726 movw $WC_LED, %dx
727 movb $0xde, %al
728 outb (%dx)
729 #endif
731 #if SERIAL
732 movw $WC_COM, %dx
733 movb $0x6e, %al
734 outb (%dx)
735 #endif
738 * if we are not running on the boot CPU restore stack contents by
739 * calling i_cpr_restore_stack(curthread, save_stack);
741 movq %rsp, %rbp
742 call i_cpr_bootcpuid
743 cmpl %eax, WC_CPU_ID(%rbx)
744 je 2f
746 movq %gs:CPU_THREAD, %rdi
747 movq WC_SAVED_STACK(%rbx), %rsi
748 call i_cpr_restore_stack
751 movq WC_RSP(%rbx), %rsp / restore stack pointer
754 * APIC initialization
756 movq %rsp, %rbp
759 * skip iff function pointer is NULL
761 cmpq $0, ap_mlsetup
762 je 3f
763 call *ap_mlsetup
766 call *cpr_start_cpu_func
768 / restore %rbx to the value it ahd before we called the functions above
769 movq rm_platter_va, %rbx
770 addq $WC_CPU, %rbx
772 movq WC_R8(%rbx), %r8
773 movq WC_R9(%rbx), %r9
774 movq WC_R10(%rbx), %r10
775 movq WC_R11(%rbx), %r11
776 movq WC_R12(%rbx), %r12
777 movq WC_R13(%rbx), %r13
778 movq WC_R14(%rbx), %r14
779 movq WC_R15(%rbx), %r15
780 / movq WC_RAX(%rbx), %rax
781 movq WC_RBP(%rbx), %rbp
782 movq WC_RCX(%rbx), %rcx
783 / movq WC_RDX(%rbx), %rdx
784 movq WC_RDI(%rbx), %rdi
785 movq WC_RSI(%rbx), %rsi
788 / assume that %cs does not need to be restored
789 / %ds, %es & %ss are ignored in 64bit mode
790 movw WC_SS(%rbx), %ss
791 movw WC_DS(%rbx), %ds
792 movw WC_ES(%rbx), %es
794 #if LED
795 movw $WC_LED, %dx
796 movb $0xdf, %al
797 outb (%dx)
798 #endif
800 #if SERIAL
801 movw $WC_COM, %dx
802 movb $0x6f, %al
803 outb (%dx)
804 #endif
807 movq WC_RBP(%rbx), %rbp
808 movq WC_RSP(%rbx), %rsp
810 #if LED
811 movw $WC_LED, %dx
812 movb $0xe0, %al
813 outb (%dx)
814 #endif
816 #if SERIAL
817 movw $WC_COM, %dx
818 movb $0x70, %al
819 outb (%dx)
820 #endif
823 movq WC_RCX(%rbx), %rcx
825 pushq WC_EFLAGS(%rbx) / restore flags
826 popfq
828 #if LED
829 movw $WC_LED, %dx
830 movb $0xe1, %al
831 outb (%dx)
832 #endif
834 #if SERIAL
835 movw $WC_COM, %dx
836 movb $0x71, %al
837 outb (%dx)
838 #endif
841 * can not use outb after this point, because doing so would mean using
842 * %dx which would modify %rdx which is restored here
845 movq %rbx, %rax
846 movq WC_RDX(%rax), %rdx
847 movq WC_RBX(%rax), %rbx
849 leave
851 movq WC_RETADDR(%rax), %rax
852 movq %rax, (%rsp) / return to caller of wc_save_context
854 xorl %eax, %eax / at wakeup return 0
858 SET_SIZE(wc_rm_start)
860 ENTRY_NP(asmspin)
862 movl %edi, %ecx
864 loop A1
866 SET_SIZE(asmspin)
868 .globl wc_rm_end
869 wc_rm_end:
872 #elif defined(__i386)
874 ENTRY_NP(wc_rm_start)
876 /entry: jmp entry / stop here for HDT
879 movw %cs, %ax
880 movw %ax, %ds / establish ds ...
881 movw %ax, %ss / ... and ss:esp
882 D16 movl $WC_STKSTART, %esp
884 #if LED
885 D16 movl $WC_LED, %edx
886 D16 movb $0xd1, %al
887 outb (%dx)
888 #endif
890 #if SERIAL
891 D16 movl $WC_COM, %edx
892 D16 movb $0x61, %al
893 outb (%dx)
894 #endif
897 D16 call vgainit
898 D16 call kbdinit
899 D16 call cominit
901 #if LED
902 D16 movl $WC_LED, %edx
903 D16 movb $0xd2, %al
904 outb (%dx)
905 #endif
907 #if SERIAL
908 D16 movl $WC_COM, %edx
909 D16 movb $0x62, %al
910 outb (%dx)
911 #endif
913 D16 A16 movl $WC_CPU, %ebx / base add of wc_cpu_t
915 #if LED
916 D16 movb $0xd3, %al
917 outb $WC_LED
918 #endif
920 #if SERIAL
921 D16 movl $WC_COM, %edx
922 D16 movb $0x63, %al
923 outb (%dx)
924 #endif
926 D16 A16 movl %cs:WC_DS(%ebx), %edx / %ds post prot/paging transit
928 #if LED
929 D16 movb $0xd4, %al
930 outb $WC_LED
931 #endif
933 D16 A16 lgdt %cs:WC_GDT(%ebx) / restore gdt and idtr
934 D16 A16 lidt %cs:WC_IDT(%ebx)
936 #if LED
937 D16 movb $0xd5, %al
938 outb $WC_LED
939 #endif
941 D16 A16 movl %cs:WC_CR4(%ebx), %eax / restore cr4
942 D16 andl $_BITNOT(CR4_PGE), %eax / don't set Global Enable yet
943 movl %eax, %cr4
945 #if LED
946 D16 movb $0xd6, %al
947 outb $WC_LED
948 #endif
950 D16 A16 movl %cs:WC_CR3(%ebx), %eax / set PDPT
951 movl %eax, %cr3
953 #if LED
954 D16 movb $0xd7, %al
955 outb $WC_LED
956 #endif
958 D16 A16 movl %cs:WC_CR0(%ebx), %eax / enable prot/paging, etc.
959 movl %eax, %cr0
961 #if LED
962 D16 movb $0xd8, %al
963 outb $WC_LED
964 #endif
966 D16 A16 movl %cs:WC_VIRTADDR(%ebx), %ebx / virtaddr of wc_cpu_t
968 #if LED
969 D16 movb $0xd9, %al
970 outb $WC_LED
971 #endif
973 #if LED
974 D16 movb $0xda, %al
975 outb $WC_LED
976 #endif
978 jmp flush / flush prefetch queue
979 flush:
980 D16 pushl $KCS_SEL
981 D16 pushl $kernel_wc_code
982 D16 lret / re-appear at kernel_wc_code
986 * Support routine to re-initialize VGA subsystem
988 vgainit:
989 D16 ret
992 * Support routine to re-initialize keyboard (which is USB - help!)
994 kbdinit:
995 D16 ret
998 * Support routine to re-initialize COM ports to something sane for debug output
1000 cominit:
1001 #if DEBUG
1003 * on debug kernels we need to initialize COM1 & COM2 here, so that
1004 * we can get debug output before the asy driver has resumed
1007 / select COM1
1008 D16 movl $_CONST(COM1+LCR), %edx
1009 D16 movb $DLAB, %al / divisor latch
1010 outb (%dx)
1012 D16 movl $_CONST(COM1+DLL), %edx / divisor latch lsb
1013 D16 movb $B9600L, %al / divisor latch
1014 outb (%dx)
1016 D16 movl $_CONST(COM1+DLH), %edx / divisor latch hsb
1017 D16 movb $B9600H, %al / divisor latch
1018 outb (%dx)
1020 D16 movl $_CONST(COM1+LCR), %edx / select COM1
1021 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1022 outb (%dx)
1024 D16 movl $_CONST(COM1+MCR), %edx / select COM1
1025 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1026 outb (%dx)
1028 / select COM2
1029 D16 movl $_CONST(COM2+LCR), %edx
1030 D16 movb $DLAB, %al / divisor latch
1031 outb (%dx)
1033 D16 movl $_CONST(COM2+DLL), %edx / divisor latch lsb
1034 D16 movb $B9600L, %al / divisor latch
1035 outb (%dx)
1037 D16 movl $_CONST(COM2+DLH), %edx / divisor latch hsb
1038 D16 movb $B9600H, %al / divisor latch
1039 outb (%dx)
1041 D16 movl $_CONST(COM2+LCR), %edx / select COM1
1042 D16 movb $_CONST(STOP1|BITS8), %al / 1 stop bit, 8bit word len
1043 outb (%dx)
1045 D16 movl $_CONST(COM2+MCR), %edx / select COM1
1046 D16 movb $_CONST(RTS|DTR), %al / 1 stop bit, 8bit word len
1047 outb (%dx)
1048 #endif /* DEBUG */
1050 D16 ret
1052 .globl wc_rm_end
1053 wc_rm_end:
1056 .globl kernel_wc_code
1057 kernel_wc_code:
1058 / At this point we are with kernel's cs and proper eip.
1059 / We will be executing not from the copy in real mode platter,
1060 / but from the original code where boot loaded us.
1061 / By this time GDT and IDT are loaded as is cr0, cr3 and cr4.
1062 / %ebx is wc_cpu
1063 / %dx is our ds
1065 #if LED
1066 D16 movb $0xdb, %al
1067 outb $WC_LED
1068 #endif
1070 / got here OK
1072 movw %dx, %ds / $KDS_SEL
1074 #if LED
1075 movb $0xdc, %al
1076 outb $WC_LED
1077 #endif
1080 * Before proceeding, enable usage of the page table NX bit if
1081 * that's how the page tables are set up.
1083 bt $X86FSET_NX, x86_featureset
1084 jnc 1f
1085 movl $MSR_AMD_EFER, %ecx
1086 rdmsr
1087 orl $AMD_EFER_NXE, %eax
1088 wrmsr
1091 movl WC_CR4(%ebx), %eax / restore full cr4 (with Global Enable)
1092 movl %eax, %cr4
1095 lldt WC_LDT(%ebx) / $LDT_SEL
1097 movzwl WC_TR(%ebx), %eax / clear TSS busy bit
1098 addl WC_GDT+2(%ebx), %eax
1099 andl $_BITNOT(0x200), 4(%eax)
1100 ltr WC_TR(%ebx) / $UTSS_SEL
1102 movw WC_SS(%ebx), %ss / restore segment registers
1103 movw WC_ES(%ebx), %es
1104 movw WC_FS(%ebx), %fs
1105 movw WC_GS(%ebx), %gs
1108 * set the stack pointer to point into the identity mapped page
1109 * temporarily, so we can make function calls
1111 .globl rm_platter_va
1112 movl rm_platter_va, %eax
1113 movl $WC_STKSTART, %esp
1114 addl %eax, %esp
1115 movl %esp, %ebp
1118 * if we are not running on the boot CPU restore stack contents by
1119 * calling i_cpr_restore_stack(curthread, save_stack);
1121 call i_cpr_bootcpuid
1122 cmpl %eax, WC_CPU_ID(%ebx)
1123 je 2f
1125 pushl WC_SAVED_STACK(%ebx)
1126 pushl %gs:CPU_THREAD
1127 call i_cpr_restore_stack
1128 addl $0x10, %esp
1131 movl WC_ESP(%ebx), %esp
1132 movl %esp, %ebp
1134 movl WC_RETADDR(%ebx), %eax / return to caller of wc_save_context
1135 movl %eax, (%esp)
1138 * APIC initialization, skip iff function pointer is NULL
1140 cmpl $0, ap_mlsetup
1141 je 3f
1142 call *ap_mlsetup
1145 call *cpr_start_cpu_func
1147 pushl WC_EFLAGS(%ebx) / restore flags
1148 popfl
1150 movl WC_EDI(%ebx), %edi / restore general registers
1151 movl WC_ESI(%ebx), %esi
1152 movl WC_EBP(%ebx), %ebp
1153 movl WC_EBX(%ebx), %ebx
1155 /exit: jmp exit / stop here for HDT
1157 xorl %eax, %eax / at wakeup return 0
1160 SET_SIZE(wc_rm_start)
1163 #endif /* defined(__amd64) */
1165 #endif /* lint */