1/*	$NetBSD$	*/
2
3/*-
4 * Copyright (c) 1998, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum, and by Andrew Doran.
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 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Functions to provide access to i386-specific instructions.
34 *
35 * These are _not_ shared with NetBSD/xen.
36 */
37
38#include <machine/asm.h>
39__KERNEL_RCSID(0, "$NetBSD$");
40
41#include <machine/specialreg.h>
42#include <machine/segments.h>
43
44#include "assym.h"
45
46ENTRY(invlpg)
47	movl	4(%esp), %eax
48	invlpg	(%eax)
49	ret
50END(invlpg)
51
52ENTRY(lldt)
53	movl	4(%esp), %eax
54	cmpl	%eax, CPUVAR(CURLDT)
55	jne	1f
56	ret
571:
58	movl	%eax, CPUVAR(CURLDT)
59	lldt	%ax
60	ret
61END(lldt)
62
63ENTRY(ltr)
64	movl	4(%esp), %eax
65	ltr	%ax
66	ret
67END(ltr)
68
69ENTRY(lcr0)
70	movl	4(%esp), %eax
71	movl	%eax, %cr0
72	ret
73END(lcr0)
74
75ENTRY(rcr0)
76	movl	%cr0, %eax
77	ret
78END(rcr0)
79
80ENTRY(lcr3)
81	movl	4(%esp), %eax
82	movl	%eax, %cr3
83	ret
84END(lcr3)
85
86/*
87 * Big hammer: flush all TLB entries, including ones from PTE's
88 * with the G bit set.  This should only be necessary if TLB
89 * shootdown falls far behind.
90 *
91 * Intel Architecture Software Developer's Manual, Volume 3,
92 *	System Programming, section 9.10, "Invalidating the
93 * Translation Lookaside Buffers (TLBS)":
94 * "The following operations invalidate all TLB entries, irrespective
95 * of the setting of the G flag:
96 * ...
97 * "(P6 family processors only): Writing to control register CR4 to
98 * modify the PSE, PGE, or PAE flag."
99 *
100 * (the alternatives not quoted above are not an option here.)
101 *
102 * If PGE is not in use, we reload CR3.  Check for the PGE feature
103 * first since i486 does not have CR4.  Note: the feature flag may
104 * be present while the actual PGE functionality not yet enabled.
105 */
106ENTRY(tlbflushg)
107	testl	$CPUID_PGE, _C_LABEL(cpu_feature)
108	jz	1f
109	movl	%cr4, %eax
110	testl	$CR4_PGE, %eax
111	jz	1f
112	movl	%eax, %edx
113	andl	$~CR4_PGE, %edx
114	movl	%edx, %cr4
115	movl	%eax, %cr4
116	ret
117END(tlbflushg)
118
119ENTRY(tlbflush)
1201:
121	movl	%cr3, %eax
122	movl	%eax, %cr3
123	ret
124END(tlbflush)
125
126ENTRY(ldr6)
127	movl	4(%esp), %eax
128	movl	%eax, %dr6
129	ret
130END(ldr6)
131
132ENTRY(rdr6)
133	movl	%dr6, %eax
134	ret
135END(rdr6)
136
137ENTRY(rcr2)
138	movl	%cr2, %eax
139	ret
140END(rcr2)
141
142ENTRY(lcr2)
143	movl	4(%esp), %eax
144	movl	%eax, %cr2
145	ret
146END(lcr2)
147
148ENTRY(wbinvd)
149	wbinvd
150	ret
151END(wbinvd)
152
153ENTRY(x86_disable_intr)
154	cli
155	ret
156END(x86_disable_intr)
157
158ENTRY(x86_enable_intr)
159	sti
160	ret
161END(x86_enable_intr)
162
163/*
164 * void lgdt(struct region_descriptor *rdp);
165 *
166 * Load a new GDT pointer (and do any necessary cleanup).
167 * XXX It's somewhat questionable whether reloading all the segment registers
168 * is necessary, since the actual descriptor data is not changed except by
169 * process creation and exit, both of which clean up via task switches.  OTOH,
170 * this only happens at run time when the GDT is resized.
171 */
172ENTRY(lgdt)
173	/* Reload the descriptor table. */
174	movl	4(%esp), %eax
175	lgdt	(%eax)
176	/* Flush the prefetch queue. */
177	jmp	1f
178	nop
1791:	/* Reload "stale" selectors. */
180	movl	$GSEL(GDATA_SEL, SEL_KPL), %eax
181	movl	%eax, %ds
182	movl	%eax, %es
183	movl	%eax, %gs
184	movl	%eax, %ss
185	movl	$GSEL(GCPU_SEL, SEL_KPL), %eax
186	movl	%eax, %fs
187	jmp	_C_LABEL(x86_flush)
188END(lgdt)
189
190ENTRY(tsc_get_timecount)
191	movl	CPUVAR(CURLWP), %ecx
1921:
193	pushl	L_NCSW(%ecx)
194	rdtsc
195	addl	CPUVAR(CC_SKEW), %eax
196	popl	%edx
197	cmpl	%edx, L_NCSW(%ecx)
198	jne	2f
199	ret
2002:
201	jmp	1b
202END(tsc_get_timecount)
203