xref: /openbsd/sys/arch/amd64/amd64/locore.S (revision 7196220c)
1*7196220cSmlarkin/*	$OpenBSD: locore.S,v 1.73 2015/11/09 01:08:56 mlarkin Exp $	*/
2b5b9857bSart/*	$NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $	*/
3f5df1827Smickey
4f5df1827Smickey/*
5f5df1827Smickey * Copyright-o-rama!
6f5df1827Smickey */
7f5df1827Smickey
8f5df1827Smickey/*
9f5df1827Smickey * Copyright (c) 2001 Wasabi Systems, Inc.
10f5df1827Smickey * All rights reserved.
11f5df1827Smickey *
12f5df1827Smickey * Written by Frank van der Linden for Wasabi Systems, Inc.
13f5df1827Smickey *
14f5df1827Smickey * Redistribution and use in source and binary forms, with or without
15f5df1827Smickey * modification, are permitted provided that the following conditions
16f5df1827Smickey * are met:
17f5df1827Smickey * 1. Redistributions of source code must retain the above copyright
18f5df1827Smickey *    notice, this list of conditions and the following disclaimer.
19f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright
20f5df1827Smickey *    notice, this list of conditions and the following disclaimer in the
21f5df1827Smickey *    documentation and/or other materials provided with the distribution.
22f5df1827Smickey * 3. All advertising materials mentioning features or use of this software
23f5df1827Smickey *    must display the following acknowledgement:
24f5df1827Smickey *      This product includes software developed for the NetBSD Project by
25f5df1827Smickey *      Wasabi Systems, Inc.
26f5df1827Smickey * 4. The name of Wasabi Systems, Inc. may not be used to endorse
27f5df1827Smickey *    or promote products derived from this software without specific prior
28f5df1827Smickey *    written permission.
29f5df1827Smickey *
30f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
31f5df1827Smickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32f5df1827Smickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33f5df1827Smickey * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
34f5df1827Smickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35f5df1827Smickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36f5df1827Smickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37f5df1827Smickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38f5df1827Smickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39f5df1827Smickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40f5df1827Smickey * POSSIBILITY OF SUCH DAMAGE.
41f5df1827Smickey */
42f5df1827Smickey
43f5df1827Smickey
44f5df1827Smickey/*-
45f5df1827Smickey * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
46f5df1827Smickey * All rights reserved.
47f5df1827Smickey *
48f5df1827Smickey * This code is derived from software contributed to The NetBSD Foundation
49f5df1827Smickey * by Charles M. Hannum.
50f5df1827Smickey *
51f5df1827Smickey * Redistribution and use in source and binary forms, with or without
52f5df1827Smickey * modification, are permitted provided that the following conditions
53f5df1827Smickey * are met:
54f5df1827Smickey * 1. Redistributions of source code must retain the above copyright
55f5df1827Smickey *    notice, this list of conditions and the following disclaimer.
56f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright
57f5df1827Smickey *    notice, this list of conditions and the following disclaimer in the
58f5df1827Smickey *    documentation and/or other materials provided with the distribution.
59f5df1827Smickey *
60f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
61f5df1827Smickey * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
62f5df1827Smickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
63f5df1827Smickey * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
64f5df1827Smickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
65f5df1827Smickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
66f5df1827Smickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
67f5df1827Smickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
68f5df1827Smickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
69f5df1827Smickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
70f5df1827Smickey * POSSIBILITY OF SUCH DAMAGE.
71f5df1827Smickey */
72f5df1827Smickey
73f5df1827Smickey/*-
74f5df1827Smickey * Copyright (c) 1990 The Regents of the University of California.
75f5df1827Smickey * All rights reserved.
76f5df1827Smickey *
77f5df1827Smickey * This code is derived from software contributed to Berkeley by
78f5df1827Smickey * William Jolitz.
79f5df1827Smickey *
80f5df1827Smickey * Redistribution and use in source and binary forms, with or without
81f5df1827Smickey * modification, are permitted provided that the following conditions
82f5df1827Smickey * are met:
83f5df1827Smickey * 1. Redistributions of source code must retain the above copyright
84f5df1827Smickey *    notice, this list of conditions and the following disclaimer.
85f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright
86f5df1827Smickey *    notice, this list of conditions and the following disclaimer in the
87f5df1827Smickey *    documentation and/or other materials provided with the distribution.
88b5b9857bSart * 3. Neither the name of the University nor the names of its contributors
89f5df1827Smickey *    may be used to endorse or promote products derived from this software
90f5df1827Smickey *    without specific prior written permission.
91f5df1827Smickey *
92f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
93f5df1827Smickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94f5df1827Smickey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95f5df1827Smickey * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
96f5df1827Smickey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
97f5df1827Smickey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
98f5df1827Smickey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
99f5df1827Smickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
100f5df1827Smickey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101f5df1827Smickey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102f5df1827Smickey * SUCH DAMAGE.
103f5df1827Smickey *
104f5df1827Smickey *	@(#)locore.s	7.3 (Berkeley) 5/13/91
105f5df1827Smickey */
106f5df1827Smickey
107f5df1827Smickey#include "assym.h"
108f5df1827Smickey#include "lapic.h"
109f5df1827Smickey#include "ioapic.h"
110f5df1827Smickey#include "ksyms.h"
1113c8478a6Sgwk#include "acpi.h"
112f5df1827Smickey
113f5df1827Smickey#include <sys/errno.h>
114f5df1827Smickey#include <sys/syscall.h>
115f5df1827Smickey
116f5df1827Smickey#include <machine/param.h>
117f5df1827Smickey#include <machine/segments.h>
118f5df1827Smickey#include <machine/specialreg.h>
119f5df1827Smickey#include <machine/trap.h>
120f5df1827Smickey#include <machine/frameasm.h>
121f5df1827Smickey
122f5df1827Smickey#if NLAPIC > 0
123f5df1827Smickey#include <machine/i82489reg.h>
124f5df1827Smickey#endif
125f5df1827Smickey
126f5df1827Smickey/*
127f5df1827Smickey * override user-land alignment before including asm.h
128f5df1827Smickey */
129f5df1827Smickey#define	ALIGN_DATA	.align	8
130f5df1827Smickey#define ALIGN_TEXT	.align 16,0x90
131f5df1827Smickey#define _ALIGN_TEXT	ALIGN_TEXT
132f5df1827Smickey
133f5df1827Smickey#include <machine/asm.h>
134f5df1827Smickey
135fbe53cacSkrw#define SET_CURPROC(proc,cpu)			\
136fbe53cacSkrw	movq	CPUVAR(SELF),cpu	;	\
137fbe53cacSkrw	movq	proc,CPUVAR(CURPROC)      ;	\
138fbe53cacSkrw	movq	cpu,P_CPU(proc)
139fbe53cacSkrw
140fbe53cacSkrw#define GET_CURPCB(reg)			movq	CPUVAR(CURPCB),reg
141fbe53cacSkrw#define SET_CURPCB(reg)			movq	reg,CPUVAR(CURPCB)
142fbe53cacSkrw
143fbe53cacSkrw
144f5df1827Smickey/* XXX temporary kluge; these should not be here */
145f5df1827Smickey/* Get definitions for IOM_BEGIN, IOM_END, and IOM_SIZE */
146f5df1827Smickey#include <dev/isa/isareg.h>
147f5df1827Smickey
148fbe53cacSkrw
149f5df1827Smickey/*
150f5df1827Smickey * Initialization
151f5df1827Smickey */
152f5df1827Smickey	.data
153f5df1827Smickey
154f5df1827Smickey#if NLAPIC > 0
155f5df1827Smickey	.align  NBPG
156f5df1827Smickey	.globl _C_LABEL(local_apic), _C_LABEL(lapic_id), _C_LABEL(lapic_tpr)
157f5df1827Smickey_C_LABEL(local_apic):
158f5df1827Smickey	.space  LAPIC_ID
159f5df1827Smickey_C_LABEL(lapic_id):
160f5df1827Smickey	.long   0x00000000
161f5df1827Smickey	.space  LAPIC_TPRI-(LAPIC_ID+4)
162f5df1827Smickey_C_LABEL(lapic_tpr):
163f5df1827Smickey	.space  LAPIC_PPRI-LAPIC_TPRI
164f5df1827Smickey_C_LABEL(lapic_ppr):
165f5df1827Smickey	.space  LAPIC_ISR-LAPIC_PPRI
166f5df1827Smickey_C_LABEL(lapic_isr):
167f5df1827Smickey	.space  NBPG-LAPIC_ISR
168f5df1827Smickey#endif
169f5df1827Smickey
170576d2332Smlarkin	.globl	_C_LABEL(cpu_id),_C_LABEL(cpu_vendor)
171f5df1827Smickey	.globl	_C_LABEL(cpuid_level),_C_LABEL(cpu_feature)
172*7196220cSmlarkin	.globl	_C_LABEL(cpu_ebxfeature)
1736995b18fShaesbaert	.globl	_C_LABEL(cpu_ecxfeature),_C_LABEL(ecpu_ecxfeature)
17407166672Smglocker	.globl	_C_LABEL(cpu_perf_eax)
17507166672Smglocker	.globl	_C_LABEL(cpu_perf_ebx)
17607166672Smglocker	.globl	_C_LABEL(cpu_perf_edx)
17707166672Smglocker	.globl	_C_LABEL(cpu_apmi_edx)
178c7636a68Smlarkin	.globl	_C_LABEL(ssym),_C_LABEL(esym),_C_LABEL(boothowto),_C_LABEL(bootdev)
1796483bf47Sderaadt	.globl	_C_LABEL(bootinfo), _C_LABEL(bootinfo_size), _C_LABEL(atdevbase)
180f5df1827Smickey	.globl	_C_LABEL(proc0paddr),_C_LABEL(PTDpaddr)
181f5df1827Smickey	.globl	_C_LABEL(biosbasemem),_C_LABEL(biosextmem)
1826483bf47Sderaadt	.globl	_C_LABEL(bootapiver)
18336414dbbSmlarkin	.globl	_C_LABEL(pg_nx)
184f5df1827Smickey_C_LABEL(cpu_id):	.long	0	# saved from `cpuid' instruction
185f5df1827Smickey_C_LABEL(cpu_feature):	.long	0	# feature flags from 'cpuid'
186f5df1827Smickey					#   instruction
187*7196220cSmlarkin_C_LABEL(cpu_ebxfeature):.long	0	# ext. ebx feature flags from 'cpuid'
188*7196220cSmlarkin_C_LABEL(cpu_ecxfeature):.long	0	# ext. ecx feature flags from 'cpuid'
1896995b18fShaesbaert_C_LABEL(ecpu_ecxfeature):.long	0	# extended ecx feature flags
19007166672Smglocker_C_LABEL(cpu_perf_eax):	.long	0	# arch. perf. mon. flags from 'cpuid'
19107166672Smglocker_C_LABEL(cpu_perf_ebx):	.long	0	# arch. perf. mon. flags from 'cpuid'
19207166672Smglocker_C_LABEL(cpu_perf_edx):	.long	0	# arch. perf. mon. flags from 'cpuid'
19307166672Smglocker_C_LABEL(cpu_apmi_edx):	.long	0	# adv. power mgmt. info. from 'cpuid'
194f5df1827Smickey_C_LABEL(cpuid_level):	.long	-1	# max. level accepted by 'cpuid'
195f5df1827Smickey					#   instruction
196f5df1827Smickey_C_LABEL(cpu_vendor):	.space	16	# vendor string returned by `cpuid'
197f5df1827Smickey					#   instruction
198c7636a68Smlarkin_C_LABEL(ssym):		.quad	0	# ptr to start of syms
199f5df1827Smickey_C_LABEL(esym):		.quad	0	# ptr to end of syms
200f5df1827Smickey_C_LABEL(atdevbase):	.quad	0	# location of start of iomem in virtual
201e9dacf7aStom_C_LABEL(bootapiver):	.long	0	# /boot API version
202f431e893Smillert_C_LABEL(bootdev):	.long	0	# device we booted from
203f5df1827Smickey_C_LABEL(proc0paddr):	.quad	0
204f5df1827Smickey_C_LABEL(PTDpaddr):	.quad	0	# paddr of PTD, for libkvm
205f5df1827Smickey#ifndef REALBASEMEM
206f5df1827Smickey_C_LABEL(biosbasemem):	.long	0	# base memory reported by BIOS
207f5df1827Smickey#else
208f5df1827Smickey_C_LABEL(biosbasemem):	.long	REALBASEMEM
209f5df1827Smickey#endif
210f5df1827Smickey#ifndef REALEXTMEM
211f5df1827Smickey_C_LABEL(biosextmem):	.long	0	# extended memory reported by BIOS
212f5df1827Smickey#else
213f5df1827Smickey_C_LABEL(biosextmem):	.long	REALEXTMEM
214f5df1827Smickey#endif
21536414dbbSmlarkin_C_LABEL(pg_nx):	.quad	0	# NX PTE bit (if CPU supports)
216f5df1827Smickey
217f5df1827Smickey#define	_RELOC(x)	((x) - KERNBASE)
218f5df1827Smickey#define	RELOC(x)	_RELOC(_C_LABEL(x))
219f5df1827Smickey
220f5df1827Smickey	.globl	gdt64
221f5df1827Smickey
222f5df1827Smickeygdt64:
223029cc5b9Smikeb	.word	gdt64_end-gdt64_start-1
224f5df1827Smickey	.quad	_RELOC(gdt64_start)
225f5df1827Smickey.align 64
226f5df1827Smickey
227f5df1827Smickeygdt64_start:
228f5df1827Smickey	.quad 0x0000000000000000	/* always empty */
229f5df1827Smickey	.quad 0x00af9a000000ffff	/* kernel CS */
230f5df1827Smickey	.quad 0x00cf92000000ffff	/* kernel DS */
231f5df1827Smickeygdt64_end:
232f5df1827Smickey
233f5df1827Smickeyfarjmp64:
234f5df1827Smickey	.long	longmode-KERNBASE
235f5df1827Smickey	.word	GSEL(GCODE_SEL, SEL_KPL)
236f5df1827Smickey
237f5df1827Smickey	.space 512
238f5df1827Smickeytmpstk:
239f5df1827Smickey
240f5df1827Smickey	.globl _C_LABEL(cpu_private)
241f5df1827Smickey	.comm _C_LABEL(cpu_private),NBPG,NBPG
242f5df1827Smickey
243f5df1827Smickey/*
244f5df1827Smickey * Some hackage to deal with 64bit symbols in 32 bit mode.
245e9dacf7aStom * This may not be needed if things are cleaned up a little.
246f5df1827Smickey */
247f5df1827Smickey
248f5df1827Smickey	.text
249f5df1827Smickey	.globl	_C_LABEL(kernel_text)
250f5df1827Smickey	.set	_C_LABEL(kernel_text),KERNTEXTOFF
251f5df1827Smickey
252f5df1827Smickey	.code32
253f5df1827Smickey
254f5df1827Smickey	.globl	start
255f5df1827Smickeystart:	movw	$0x1234,0x472			# warm boot
256f5df1827Smickey
257f5df1827Smickey	/*
258f5df1827Smickey	 * Load parameters from stack
259930756e7Stom	 * (howto, bootdev, bootapiver, esym, extmem, cnvmem, ac, av)
260f5df1827Smickey	 */
261f5df1827Smickey	movl	4(%esp),%eax
262930756e7Stom	movl	%eax, RELOC(boothowto)
263a47f7207Smickey	movl	8(%esp),%eax
264930756e7Stom	movl	%eax, RELOC(bootdev)
265f5df1827Smickey
26619edda9eSbluhm	/*
26719edda9eSbluhm	 * Syms are placed after last load and bss of the kernel.
26819edda9eSbluhm	 * XXX Boot ignores 2MB roundup of _end, so esyms can be < _end.
26919edda9eSbluhm	 */
270f5df1827Smickey	movl	16(%esp), %eax
271f5df1827Smickey	testl   %eax,%eax
272f5df1827Smickey	jz      1f
273f5df1827Smickey	addl    $KERNBASE_LO,%eax
274a47f7207Smickey	movl    $RELOC(esym),%ebp
275f5df1827Smickey	movl    %eax,(%ebp)
276f5df1827Smickey	movl    $KERNBASE_HI,4(%ebp)
277a47f7207Smickey1:
278f5df1827Smickey	movl	20(%esp), %eax
279a47f7207Smickey	movl	%eax, RELOC(biosextmem)
280f5df1827Smickey	movl	24(%esp), %eax
281a47f7207Smickey	movl	%eax, RELOC(biosbasemem)
282f5df1827Smickey
283e9dacf7aStom	movl	12(%esp), %eax
284e9dacf7aStom	movl	%eax, RELOC(bootapiver)
2856483bf47Sderaadt
2866483bf47Sderaadt	/*
2876483bf47Sderaadt	 * Copy the boot arguments to bootinfo[] in machdep.c.
2886483bf47Sderaadt	 *
289a2932691Smlarkin	 * We are passed the size of the data /boot passed to us in
290a2932691Smlarkin	 * 28(%esp). We copy up to bootinfo_size bytes of data into
291a2932691Smlarkin	 * bootinfo and report back how much we copied in bootinfo_size.
2926483bf47Sderaadt	 *
2936483bf47Sderaadt	 * machdep.c can then take action if bootinfo_size >= bootinfo[]
2946483bf47Sderaadt	 * (which would meant that we may have been passed too much data).
2956483bf47Sderaadt	 */
296e9dacf7aStom 	movl	28(%esp), %eax
2976483bf47Sderaadt	movl	%eax, %ecx
2986483bf47Sderaadt	cmpl	RELOC(bootinfo_size), %ecx	/* Too much? */
299a2932691Smlarkin	jb	bi_size_ok
3006483bf47Sderaadt	movl	RELOC(bootinfo_size), %ecx	/* Only copy this much */
3016483bf47Sderaadtbi_size_ok:
3026483bf47Sderaadt	movl	%eax, RELOC(bootinfo_size)	/* Report full amount */
3036483bf47Sderaadt
3046483bf47Sderaadt	movl	$RELOC(bootinfo), %edi		/* Destination */
3056483bf47Sderaadt	movl	32(%esp), %esi			/* Source */
3066483bf47Sderaadt	rep movsb				/* Copy this many bytes */
307e9dacf7aStom
308f5df1827Smickey	/* First, reset the PSL. */
309f5df1827Smickey	pushl	$PSL_MBO
310f5df1827Smickey	popfl
311f5df1827Smickey
312f5df1827Smickey	xorl	%eax,%eax
313f5df1827Smickey	cpuid
314f5df1827Smickey	movl	%eax,RELOC(cpuid_level)
315f5df1827Smickey	movl	$RELOC(cpu_vendor),%ebp
316f5df1827Smickey	movl	%ebx,(%ebp)
317f5df1827Smickey	movl	%edx,4(%ebp)
318f5df1827Smickey	movl	%ecx,8(%ebp)
319f5df1827Smickey	movl	$0,  12(%ebp)
320f5df1827Smickey
321f5df1827Smickey	movl	$1,%eax
322f5df1827Smickey	cpuid
323f5df1827Smickey	movl	%eax,RELOC(cpu_id)
324*7196220cSmlarkin	movl	%ebx,RELOC(cpu_ebxfeature)
325c098ddcfSjsg	movl	%ecx,RELOC(cpu_ecxfeature)
326f5df1827Smickey	movl	%edx,RELOC(cpu_feature)
327f5df1827Smickey
32807166672Smglocker	movl	$0x0a,%eax
32907166672Smglocker	cpuid
33007166672Smglocker	movl	%eax,RELOC(_C_LABEL(cpu_perf_eax))
33107166672Smglocker	movl	%ebx,RELOC(_C_LABEL(cpu_perf_ebx))
33207166672Smglocker	movl	%edx,RELOC(_C_LABEL(cpu_perf_edx))
33307166672Smglocker
3341fef3300Smickey	movl	$0x80000001, %eax
3351fef3300Smickey	cpuid
3361fef3300Smickey	andl	$CPUID_NXE, %edx	/* other bits may clash */
33736414dbbSmlarkin	jz	cont
33836414dbbSmlarkin
33936414dbbSmlarkin	/*
34036414dbbSmlarkin	 * We have NX, set pg_nx accordingly.
34136414dbbSmlarkin	 * NX bit is bit 63 (bit 31 of the second 32 bit dword) - need
34236414dbbSmlarkin	 * to use 32 bit registers here
34336414dbbSmlarkin	 */
34436414dbbSmlarkin	pushl	%edx
34536414dbbSmlarkin	movl	RELOC((pg_nx + 4)), %edx	/* Second dword */
34636414dbbSmlarkin	orl	$0x80000000, %edx 		/* Bit 31 (really 63) */
34736414dbbSmlarkin	movl	%edx, RELOC((pg_nx + 4))
34836414dbbSmlarkin	popl	%edx
34936414dbbSmlarkincont:
3501fef3300Smickey	orl     %edx, RELOC(cpu_feature)
3511fef3300Smickey
35207166672Smglocker	movl	$0x80000007,%eax
35307166672Smglocker	cpuid
35407166672Smglocker	movl	%edx,RELOC(_C_LABEL(cpu_apmi_edx))
35507166672Smglocker
356f5df1827Smickey	/*
357f5df1827Smickey	 * Finished with old stack; load new %esp now instead of later so we
358f5df1827Smickey	 * can trace this code without having to worry about the trace trap
359f5df1827Smickey	 * clobbering the memory test or the zeroing of the bss+bootstrap page
360f5df1827Smickey	 * tables.
361f5df1827Smickey	 *
362f5df1827Smickey	 * The boot program should check:
363f5df1827Smickey	 *	text+data <= &stack_variable - more_space_for_stack
364f5df1827Smickey	 *	text+data+bss+pad+space_for_page_tables <= end_of_memory
365f5df1827Smickey	 * Oops, the gdt is in the carcass of the boot program so clearing
366f5df1827Smickey	 * the rest of memory is still not possible.
367f5df1827Smickey	 */
368f5df1827Smickey	movl	$RELOC(tmpstk),%esp
369f5df1827Smickey
370f5df1827Smickey/*
371f5df1827Smickey * Virtual address space of kernel:
372f5df1827Smickey *
373f5df1827Smickey * text | data | bss | [syms] | page dir | proc0 kstack | L1 ptp | L2 ptp | L3
374f5df1827Smickey *			      0          1       2      3
375f5df1827Smickey */
376f5df1827Smickey
377f5df1827Smickey#if L2_SLOT_KERNBASE > 0
378f5df1827Smickey#define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1))
379f5df1827Smickey#else
380f5df1827Smickey#define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1)
381f5df1827Smickey#endif
382f5df1827Smickey
383f5df1827Smickey#if L3_SLOT_KERNBASE > 0
384f5df1827Smickey#define TABLE_L3_ENTRIES (2 * NKL3_KIMG_ENTRIES)
385f5df1827Smickey#else
386f5df1827Smickey#define TABLE_L3_ENTRIES NKL3_KIMG_ENTRIES
387f5df1827Smickey#endif
388f5df1827Smickey
389f5df1827Smickey
390f5df1827Smickey#define PROC0_PML4_OFF	0
391f5df1827Smickey#define PROC0_STK_OFF	(PROC0_PML4_OFF + NBPG)
392f5df1827Smickey#define PROC0_PTP3_OFF	(PROC0_STK_OFF + UPAGES * NBPG)
393f5df1827Smickey#define PROC0_PTP2_OFF	(PROC0_PTP3_OFF + NKL4_KIMG_ENTRIES * NBPG)
394f5df1827Smickey#define PROC0_PTP1_OFF	(PROC0_PTP2_OFF + TABLE_L3_ENTRIES * NBPG)
395f00c9240Sart#define	PROC0_DMP3_OFF	(PROC0_PTP1_OFF + TABLE_L2_ENTRIES * NBPG)
396f00c9240Sart#define PROC0_DMP2_OFF	(PROC0_DMP3_OFF + NDML3_ENTRIES * NBPG)
397f5df1827Smickey#define TABLESIZE \
398f00c9240Sart    ((NKL4_KIMG_ENTRIES + TABLE_L3_ENTRIES + TABLE_L2_ENTRIES + 1 + UPAGES + \
399f00c9240Sart	NDML3_ENTRIES + NDML2_ENTRIES) * NBPG)
400f5df1827Smickey
401f5df1827Smickey#define fillkpt \
402f5df1827Smickey1:	movl	%eax,(%ebx)	; 	/* store phys addr */ \
403f5df1827Smickey	movl	$0,4(%ebx)	; 	/* upper 32 bits 0 */ \
404f5df1827Smickey	addl	$8,%ebx		; 	/* next pte/pde */ \
405f5df1827Smickey	addl	$NBPG,%eax	; 	/* next phys page */ \
40636414dbbSmlarkin	loop	1b		;	/* till finished */
407f5df1827Smickey
408f5df1827Smickey
40936414dbbSmlarkin#define fillkpt_nx \
41036414dbbSmlarkin	pushl	%ebp				;	/* save */ \
41136414dbbSmlarkin1:	movl	%eax,(%ebx)			; 	/* store phys addr */ \
41236414dbbSmlarkin	movl	RELOC((pg_nx + 4)), %ebp	;	/* NX bit? */ \
41336414dbbSmlarkin	movl	%ebp,4(%ebx)			; 	/* upper 32 bits */ \
41436414dbbSmlarkin	addl	$8,%ebx				; 	/* next pte/pde */ \
41536414dbbSmlarkin	addl	$NBPG,%eax			; 	/* next phys page */ \
41636414dbbSmlarkin	loop	1b				;	/* till finished */ \
41736414dbbSmlarkin	popl	%ebp
41836414dbbSmlarkin
419f5df1827Smickey	/* Find end of kernel image. */
420f5df1827Smickey	movl	$RELOC(end),%edi
4218f48279bStedu#if (NKSYMS || defined(DDB)) && !defined(SYMTAB_SPACE)
422f5df1827Smickey	/* Save the symbols (if loaded). */
423f5df1827Smickey	movl	RELOC(esym),%eax
424f5df1827Smickey	testl	%eax,%eax
425f5df1827Smickey	jz	1f
426f5df1827Smickey	subl	$KERNBASE_LO,%eax	/* XXX */
42719edda9eSbluhm	/* Page tables must be after symbols and after kernel image. */
42819edda9eSbluhm	cmpl	%eax,%edi
42919edda9eSbluhm	jg	1f
430f5df1827Smickey	movl	%eax,%edi
431f5df1827Smickey1:
432f5df1827Smickey#endif
433f5df1827Smickey	/* Clear tables */
434f5df1827Smickey	movl	%edi,%esi
435f5df1827Smickey	addl	$PGOFSET,%esi
436f5df1827Smickey	andl	$~PGOFSET,%esi
437f5df1827Smickey
438f5df1827Smickey	movl	%esi,%edi
439f5df1827Smickey	xorl	%eax,%eax
440f5df1827Smickey	cld
441f5df1827Smickey	movl	$TABLESIZE,%ecx
442f5df1827Smickey	shrl	$2,%ecx
443f5df1827Smickey	rep
444f5df1827Smickey	stosl
445f5df1827Smickey
446f5df1827Smickey	leal	(PROC0_PTP1_OFF)(%esi), %ebx
447f5df1827Smickey
448f5df1827Smickey	/*
449f5df1827Smickey	 * Compute etext - KERNBASE. This can't be > 4G, or we can't deal
450f5df1827Smickey	 * with it anyway, since we can't load it in 32 bit mode. So use
451f5df1827Smickey	 * the bottom 32 bits.
452f5df1827Smickey	 */
453f5df1827Smickey	movl	$RELOC(etext),%edx
454f5df1827Smickey	addl	$PGOFSET,%edx
455f5df1827Smickey	andl	$~PGOFSET,%edx
456f5df1827Smickey
457f5df1827Smickey	/*
458f5df1827Smickey	 * Skip the first MB.
459f5df1827Smickey	 */
460f5df1827Smickey	movl	$(KERNTEXTOFF_LO - KERNBASE_LO),%eax
461f5df1827Smickey	movl	%eax,%ecx
462f5df1827Smickey	shrl	$(PGSHIFT-3),%ecx	/* ((n >> PGSHIFT) << 3) for # pdes */
463f5df1827Smickey	addl	%ecx,%ebx
464f5df1827Smickey
46536414dbbSmlarkin	/* Map kernel text RO, X */
466f5df1827Smickey	movl	%edx,%ecx
467f5df1827Smickey	subl	%eax,%ecx
468f5df1827Smickey	shrl	$PGSHIFT,%ecx
469f5df1827Smickey	orl     $(PG_V|PG_KR),%eax
470f5df1827Smickey	fillkpt
471f5df1827Smickey
47236414dbbSmlarkin	/* Map .rodata RO, NX */
4737e27549bSmlarkin	movl	$RELOC(__rodata_start), %eax
4747e27549bSmlarkin	movl	$RELOC(erodata), %ecx
4757e27549bSmlarkin	addl	$PGOFSET, %ecx
4767e27549bSmlarkin	andl	$~PGOFSET, %ecx
4777e27549bSmlarkin	subl	%eax, %ecx
4787e27549bSmlarkin	shrl	$PGSHIFT, %ecx
4797e27549bSmlarkin	orl	$(PG_V|PG_KR), %eax
48036414dbbSmlarkin	fillkpt_nx
4817e27549bSmlarkin
482c7636a68Smlarkin	/* Map the data and BSS sections RW, NX */
483c7636a68Smlarkin	movl	$RELOC(__data_start), %eax
484c7636a68Smlarkin	movl	$RELOC(__kernel_bss_end),%ecx
485c7636a68Smlarkin	addl	$PGOFSET, %ecx
486c7636a68Smlarkin	andl	$~PGOFSET, %ecx
487c7636a68Smlarkin	subl	%eax, %ecx
488c7636a68Smlarkin	shrl	$PGSHIFT,%ecx
489c7636a68Smlarkin	orl	$(PG_V|PG_KW), %eax
490c7636a68Smlarkin	fillkpt_nx
4917e27549bSmlarkin
492c7636a68Smlarkin	/* Map "hole" at end of BSS RO, NX */
493c7636a68Smlarkin	movl	$RELOC(__kernel_bss_end), %eax
494c7636a68Smlarkin	movl	$RELOC(end), %ecx
495c7636a68Smlarkin	addl	$PGOFSET, %ecx
496c7636a68Smlarkin	andl	$~PGOFSET, %ecx
497c7636a68Smlarkin	cmpl	%eax, %ecx
498c7636a68Smlarkin	je	map_syms
499c7636a68Smlarkin	subl	%eax, %ecx
500c7636a68Smlarkin	shrl	$PGSHIFT, %ecx
501c7636a68Smlarkin	orl	$(PG_V|PG_KR), %eax
502c7636a68Smlarkin	fillkpt_nx
503c7636a68Smlarkin
504c7636a68Smlarkinmap_syms:
505c7636a68Smlarkin	/* Map symbol space RO, NX */
506c7636a68Smlarkin	movl	$RELOC(end), %eax
507c7636a68Smlarkin	movl	%esi, %ecx
508c7636a68Smlarkin	addl	$PGOFSET, %ecx
509c7636a68Smlarkin	andl	$~PGOFSET, %ecx
510c7636a68Smlarkin	cmpl	%eax, %ecx
511c7636a68Smlarkin	je	map_tables
512c7636a68Smlarkin	subl	%eax, %ecx
513c7636a68Smlarkin	shrl	$PGSHIFT, %ecx
514c7636a68Smlarkin	orl	$(PG_V|PG_KR), %eax
515c7636a68Smlarkin	fillkpt_nx
516c7636a68Smlarkin
517c7636a68Smlarkinmap_tables:
518c7636a68Smlarkin	/* Map the bootstrap tables RW, NX */
519c7636a68Smlarkin	movl	%esi, %edx
520f5df1827Smickey	leal	(PG_V|PG_KW)(%edx),%eax
521f5df1827Smickey	movl	$TABLESIZE,%ecx
522f5df1827Smickey	shrl	$PGSHIFT,%ecx
52336414dbbSmlarkin	fillkpt_nx
524f5df1827Smickey
52536414dbbSmlarkin	/* Map ISA I/O mem (later atdevbase) RW, NX */
526f5df1827Smickey	movl	$(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax
527f5df1827Smickey	movl	$(IOM_SIZE>>PGSHIFT),%ecx
52836414dbbSmlarkin	fillkpt_nx
529f5df1827Smickey
53036414dbbSmlarkin	/* Set up level 2 pages (RWX) */
531f5df1827Smickey	leal    (PROC0_PTP2_OFF)(%esi),%ebx
532f5df1827Smickey	leal	(PROC0_PTP1_OFF)(%esi),%eax
533f5df1827Smickey	orl	$(PG_V|PG_KW), %eax
534f5df1827Smickey	movl	$(NKL2_KIMG_ENTRIES+1),%ecx
535f5df1827Smickey	fillkpt
536f5df1827Smickey
537f5df1827Smickey#if L2_SLOT_KERNBASE > 0
53836414dbbSmlarkin	/* If needed, set up L2 entries for actual kernel mapping (RWX) */
539f5df1827Smickey	leal	(PROC0_PTP2_OFF+ L2_SLOT_KERNBASE*8)(%esi),%ebx
540f5df1827Smickey	leal    (PROC0_PTP1_OFF)(%esi),%eax
541f5df1827Smickey	orl     $(PG_V|PG_KW), %eax
542f5df1827Smickey	movl    $(NKL2_KIMG_ENTRIES+1),%ecx
543f5df1827Smickey	fillkpt
544f5df1827Smickey#endif
545f5df1827Smickey
54636414dbbSmlarkin	/* Set up level 3 pages (RWX) */
547f5df1827Smickey	leal    (PROC0_PTP3_OFF)(%esi),%ebx
548f5df1827Smickey	leal	(PROC0_PTP2_OFF)(%esi),%eax
549f5df1827Smickey	orl	$(PG_V|PG_KW), %eax
550f5df1827Smickey	movl	$NKL3_KIMG_ENTRIES,%ecx
551f5df1827Smickey	fillkpt
552f5df1827Smickey
553f5df1827Smickey#if L3_SLOT_KERNBASE > 0
55436414dbbSmlarkin	/* If needed, set up L3 entries for actual kernel mapping (RWX) */
555f5df1827Smickey	leal	(PROC0_PTP3_OFF+ L3_SLOT_KERNBASE*8)(%esi),%ebx
556f5df1827Smickey	leal    (PROC0_PTP2_OFF)(%esi),%eax
557f5df1827Smickey	orl     $(PG_V|PG_KW), %eax
558f5df1827Smickey	movl    $NKL3_KIMG_ENTRIES,%ecx
559f5df1827Smickey	fillkpt
560f5df1827Smickey#endif
561f5df1827Smickey
56236414dbbSmlarkin	/* Set up top level entries for identity mapping (RWX) */
563f5df1827Smickey	leal    (PROC0_PML4_OFF)(%esi),%ebx
564f5df1827Smickey	leal	(PROC0_PTP3_OFF)(%esi),%eax
565f5df1827Smickey	orl	$(PG_V|PG_KW), %eax
566f5df1827Smickey	movl	$NKL4_KIMG_ENTRIES,%ecx
567f5df1827Smickey	fillkpt
568f5df1827Smickey
56936414dbbSmlarkin	/* Set up top level entries for actual kernel mapping (RWX) */
570f5df1827Smickey	leal    (PROC0_PML4_OFF + L4_SLOT_KERNBASE*8)(%esi),%ebx
571f5df1827Smickey	leal	(PROC0_PTP3_OFF)(%esi),%eax
572f5df1827Smickey	orl	$(PG_V|PG_KW), %eax
573f5df1827Smickey	movl	$NKL4_KIMG_ENTRIES,%ecx
574f5df1827Smickey	fillkpt
575f5df1827Smickey
576f00c9240Sart	/*
577f00c9240Sart	 * Map the first 4 GB with the direct map. We'll map the rest
578f00c9240Sart	 * in pmap_bootstrap. But we always need the first 4GB during
579c7636a68Smlarkin	 * bootstrap. The direct map is mapped RW, NX. We also change
580c7636a68Smlarkin	 * the permissions on the 2MB pages corresponding to the kernel
581c7636a68Smlarkin	 * PAs to RO to prevent someone writing to the kernel area
582c7636a68Smlarkin	 * via the direct map.
583f00c9240Sart	 */
584f00c9240Sart	leal	(PROC0_DMP2_OFF)(%esi), %ebx
585f00c9240Sart	xorl	%eax, %eax
586f00c9240Sart	movl	$(NDML2_ENTRIES * NPDPG), %ecx
587c7636a68Smlarkin1:	orl	$(PG_V|PG_KW|PG_PS|PG_G), %eax
588c7636a68Smlarkin	cmpl	$__kernel_base_phys, %eax
589c7636a68Smlarkin	jl	store_pte
590c7636a68Smlarkin	cmpl	$__kernel_end_phys, %eax
591c7636a68Smlarkin	jg	store_pte
592c7636a68Smlarkin	andl	$(~PG_KW), %eax
593c7636a68Smlarkinstore_pte:
594c7636a68Smlarkin	movl	%eax, (%ebx)
59536414dbbSmlarkin	pushl	%ebp
59636414dbbSmlarkin	movl	RELOC((pg_nx + 4)), %ebp
59736414dbbSmlarkin	movl	%ebp, 4(%ebx)
59836414dbbSmlarkin	popl	%ebp
599f00c9240Sart	addl	$8, %ebx
600f00c9240Sart	addl	$NBPD_L2, %eax
601f00c9240Sart	loop	1b
602f00c9240Sart
603f00c9240Sart	leal	(PROC0_DMP3_OFF)(%esi), %ebx
604f00c9240Sart	leal	(PROC0_DMP2_OFF)(%esi), %eax
605f00c9240Sart	orl	$(PG_V|PG_KW), %eax
606f00c9240Sart	movl	$NDML2_ENTRIES, %ecx
60736414dbbSmlarkin	fillkpt_nx
608f00c9240Sart
609f00c9240Sart	leal	(PROC0_PML4_OFF + PDIR_SLOT_DIRECT * 8)(%esi), %ebx
610f00c9240Sart	leal	(PROC0_DMP3_OFF)(%esi), %eax
611f00c9240Sart	orl	$(PG_V|PG_KW), %eax
612f00c9240Sart	movl	$NDML3_ENTRIES, %ecx
61336414dbbSmlarkin	fillkpt_nx
614f00c9240Sart
615f5df1827Smickey	/* Install recursive top level PDE */
616f5df1827Smickey	leal	(PROC0_PML4_OFF + PDIR_SLOT_PTE*8)(%esi),%ebx
617f5df1827Smickey	leal	(PROC0_PML4_OFF)(%esi),%eax
618f5df1827Smickey	orl	$(PG_V|PG_KW),%eax
619f5df1827Smickey	movl	%eax,(%ebx)
62036414dbbSmlarkin	pushl	%ebp
62136414dbbSmlarkin	movl	RELOC((pg_nx + 4)), %ebp
62236414dbbSmlarkin	movl	%ebp, 4(%ebx)
62336414dbbSmlarkin	popl 	%ebp
624f5df1827Smickey
625f5df1827Smickey	/* Save phys. addr of PTD, for libkvm. */
626f5df1827Smickey	movl	$RELOC(PTDpaddr),%ebp
627f5df1827Smickey	movl	%esi,(%ebp)
628f5df1827Smickey	movl	$0,4(%ebp)
629f5df1827Smickey
630f5df1827Smickey	/*
631f5df1827Smickey	 * Startup checklist:
632f5df1827Smickey	 * 1. Enable PAE (and SSE while here).
633f5df1827Smickey	 */
634f5df1827Smickey	movl	%cr4,%eax
63549e2e7f9Sart	orl	$(CR4_DEFAULT),%eax
636f5df1827Smickey	movl	%eax,%cr4
637f5df1827Smickey
638f5df1827Smickey	/*
639f5df1827Smickey	 * 2. Set Long Mode Enable in EFER. Also enable the
64036414dbbSmlarkin	 *    syscall extensions and NX (if available).
641f5df1827Smickey	 */
642f5df1827Smickey	movl    $MSR_EFER,%ecx
643f5df1827Smickey	rdmsr
644f5df1827Smickey	xorl	%eax,%eax	/* XXX */
645f5df1827Smickey	orl	$(EFER_LME|EFER_SCE),%eax
64636414dbbSmlarkin	movl	RELOC((pg_nx + 4)), %ebx
647b73ba79bSmlarkin	cmpl	$0, %ebx
648b73ba79bSmlarkin	je 	write_efer
64936414dbbSmlarkin	orl	$(EFER_NXE), %eax
65036414dbbSmlarkinwrite_efer:
651f5df1827Smickey	wrmsr
652f5df1827Smickey
653f5df1827Smickey	/*
654f5df1827Smickey	 * 3. Load %cr3 with pointer to PML4.
655f5df1827Smickey	 */
656f5df1827Smickey	movl	%esi,%eax
657f5df1827Smickey	movl	%eax,%cr3
658f5df1827Smickey
659f5df1827Smickey	/*
660f5df1827Smickey	 * 4. Enable paging and the rest of it.
661f5df1827Smickey	 */
662f5df1827Smickey	movl	%cr0,%eax
663f5df1827Smickey	orl	$(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP),%eax
664f5df1827Smickey	movl	%eax,%cr0
665f5df1827Smickey	jmp	compat
666f5df1827Smickeycompat:
667f5df1827Smickey
668f5df1827Smickey	/*
669f5df1827Smickey	 * 5.
670f5df1827Smickey	 * Not quite done yet, we're now in a compatibility segment,
671f5df1827Smickey	 * in legacy mode. We must jump to a long mode segment.
672f5df1827Smickey	 * Need to set up a temporary GDT with a long mode segment
673f5df1827Smickey	 * in it to do that.
674f5df1827Smickey	 */
675f5df1827Smickey
676f5df1827Smickey	movl	$RELOC(gdt64),%eax
677f5df1827Smickey	lgdt	(%eax)
678f5df1827Smickey	movl	$RELOC(farjmp64),%eax
679f5df1827Smickey	ljmp	*(%eax)
680f5df1827Smickey
681f5df1827Smickey.code64
682f5df1827Smickeylongmode:
683f5df1827Smickey	/*
684f5df1827Smickey	 * 6.
685f5df1827Smickey	 * Finally, we're in long mode. However, we're still
686f5df1827Smickey	 * in the identity mapped area (could not jump out
687f5df1827Smickey	 * of that earlier because it would have been a > 32bit
688f5df1827Smickey	 * jump). We can do that now, so here we go.
689f5df1827Smickey	 */
690f5df1827Smickey	movabsq	$longmode_hi,%rax
691f5df1827Smickey	jmp	*%rax
692f5df1827Smickeylongmode_hi:
693f5df1827Smickey	/*
694f5df1827Smickey	 * We have arrived.
695f5df1827Smickey	 * There's no need anymore for the identity mapping in low
696f5df1827Smickey	 * memory, remove it.
697f5df1827Smickey	 */
698f5df1827Smickey	movq	$KERNBASE,%r8
699f5df1827Smickey
700f5df1827Smickey#if L2_SLOT_KERNBASE > 0
701f5df1827Smickey	movq	$(NKL2_KIMG_ENTRIES+1),%rcx
702f5df1827Smickey	leaq	(PROC0_PTP2_OFF)(%rsi),%rbx
703f5df1827Smickey	addq	%r8, %rbx
704cd0e2476Smlarkin1:	movq	$0 ,(%rbx)
705f5df1827Smickey	addq	$8,%rbx
706f5df1827Smickey	loop	1b
707f5df1827Smickey#endif
708f5df1827Smickey
709f5df1827Smickey#if L3_SLOT_KERNBASE > 0
710f5df1827Smickey	movq	$NKL3_KIMG_ENTRIES,%rcx
711f5df1827Smickey	leaq	(PROC0_PTP3_OFF)(%rsi),%rbx
712f5df1827Smickey	addq	%r8, %rbx
713cd0e2476Smlarkin1:	movq	$0 ,(%rbx)
714f5df1827Smickey	addq	$8,%rbx
715f5df1827Smickey	loop	1b
716f5df1827Smickey#endif
717f5df1827Smickey
718f5df1827Smickey	movq	$NKL4_KIMG_ENTRIES,%rcx
719f5df1827Smickey	leaq	(PROC0_PML4_OFF)(%rsi),%rbx	# old, phys  address of PML4
720b5b9857bSart	addq	%r8, %rbx			# new, virtual address of PML4
721cd0e2476Smlarkin1:	movq	$0, (%rbx)
722f5df1827Smickey	addq	$8,%rbx
723f5df1827Smickey	loop	1b
724f5df1827Smickey
725f5df1827Smickey	/* Relocate atdevbase. */
726f5df1827Smickey	movq	$(TABLESIZE+KERNBASE),%rdx
727f5df1827Smickey	addq	%rsi,%rdx
728f5df1827Smickey	movq	%rdx,_C_LABEL(atdevbase)(%rip)
729f5df1827Smickey
730c7636a68Smlarkin	/* Record start of symbols */
731c7636a68Smlarkin	movq	$__kernel_bss_end, _C_LABEL(ssym)(%rip)
732c7636a68Smlarkin
733f5df1827Smickey	/* Set up bootstrap stack. */
734f5df1827Smickey	leaq	(PROC0_STK_OFF)(%rsi),%rax
735f5df1827Smickey	addq	%r8,%rax
736f5df1827Smickey	movq	%rax,_C_LABEL(proc0paddr)(%rip)
737f5df1827Smickey	leaq	(USPACE-FRAMESIZE)(%rax),%rsp
738f5df1827Smickey	movq	%rsi,PCB_CR3(%rax)	# pcb->pcb_cr3
739f5df1827Smickey	xorq	%rbp,%rbp               # mark end of frames
740f5df1827Smickey
741f5df1827Smickey	xorw	%ax,%ax
742f5df1827Smickey	movw	%ax,%gs
743f5df1827Smickey	movw	%ax,%fs
744f5df1827Smickey
745f5df1827Smickey	/* XXX merge these */
746f5df1827Smickey	leaq	TABLESIZE(%rsi),%rdi
747f5df1827Smickey	call	_C_LABEL(init_x86_64)
748f5df1827Smickey
749f5df1827Smickey	call 	_C_LABEL(main)
750f5df1827Smickey
751f5df1827Smickey/*****************************************************************************/
752f5df1827Smickey
753f5df1827Smickey/*
754f5df1827Smickey * Signal trampoline; copied to top of user stack.
755aa7a0a27Sguenther * gdb's backtrace logic matches against the instructions in this.
756f5df1827Smickey */
757f5df1827SmickeyNENTRY(sigcode)
758f5df1827Smickey	call	*%rax
759f5df1827Smickey
760f5df1827Smickey	movq	%rsp,%rdi
761f5df1827Smickey	pushq	%rdi			/* fake return address */
762f5df1827Smickey	movq	$SYS_sigreturn,%rax
7631396572dSguenther	syscall
764f5df1827Smickey	movq	$SYS_exit,%rax
765f5df1827Smickey	syscall
766f5df1827Smickey	.globl	_C_LABEL(esigcode)
767f5df1827Smickey_C_LABEL(esigcode):
768f5df1827Smickey
769f5df1827Smickey/*
770f5df1827Smickey * void lgdt(struct region_descriptor *rdp);
771f5df1827Smickey * Change the global descriptor table.
772f5df1827Smickey */
773f5df1827SmickeyNENTRY(lgdt)
774f5df1827Smickey	/* Reload the descriptor table. */
775f5df1827Smickey	movq	%rdi,%rax
776f5df1827Smickey	lgdt	(%rax)
777f5df1827Smickey	/* Flush the prefetch q. */
778f5df1827Smickey	jmp	1f
779f5df1827Smickey	nop
780f5df1827Smickey1:	/* Reload "stale" selectors. */
781f5df1827Smickey	movl	$GSEL(GDATA_SEL, SEL_KPL),%eax
782f5df1827Smickey	movl	%eax,%ds
783f5df1827Smickey	movl	%eax,%es
784f5df1827Smickey	movl	%eax,%ss
785f5df1827Smickey	/* Reload code selector by doing intersegment return. */
786f5df1827Smickey	popq	%rax
787f5df1827Smickey	pushq	$GSEL(GCODE_SEL, SEL_KPL)
788f5df1827Smickey	pushq	%rax
789f5df1827Smickey	lretq
790f5df1827Smickey
791f5df1827SmickeyENTRY(setjmp)
792f5df1827Smickey	/*
793f5df1827Smickey	 * Only save registers that must be preserved across function
794f5df1827Smickey	 * calls according to the ABI (%rbx, %rsp, %rbp, %r12-%r15)
795f5df1827Smickey	 * and %rip.
796f5df1827Smickey	 */
797f5df1827Smickey	movq	%rdi,%rax
798f5df1827Smickey	movq	%rbx,(%rax)
799f5df1827Smickey	movq	%rsp,8(%rax)
800f5df1827Smickey	movq	%rbp,16(%rax)
801f5df1827Smickey	movq	%r12,24(%rax)
802f5df1827Smickey	movq	%r13,32(%rax)
803f5df1827Smickey	movq	%r14,40(%rax)
804f5df1827Smickey	movq	%r15,48(%rax)
805f5df1827Smickey	movq	(%rsp),%rdx
806f5df1827Smickey	movq	%rdx,56(%rax)
807f5df1827Smickey	xorl	%eax,%eax
808f5df1827Smickey	ret
809f5df1827Smickey
810f5df1827SmickeyENTRY(longjmp)
811f5df1827Smickey	movq	%rdi,%rax
812f5df1827Smickey	movq	(%rax),%rbx
813f5df1827Smickey	movq	8(%rax),%rsp
814f5df1827Smickey	movq	16(%rax),%rbp
815f5df1827Smickey	movq	24(%rax),%r12
816f5df1827Smickey	movq	32(%rax),%r13
817f5df1827Smickey	movq	40(%rax),%r14
818f5df1827Smickey	movq	48(%rax),%r15
819f5df1827Smickey	movq	56(%rax),%rdx
820f5df1827Smickey	movq	%rdx,(%rsp)
821f5df1827Smickey	xorl	%eax,%eax
822f5df1827Smickey	incl	%eax
823f5df1827Smickey	ret
824f5df1827Smickey
825f5df1827Smickey/*****************************************************************************/
826f5df1827Smickey
827f5df1827Smickey/*
82845053f4aSart * int cpu_switchto(struct proc *old, struct proc *new)
82945053f4aSart * Switch from "old" proc to "new".
830f5df1827Smickey */
83145053f4aSartENTRY(cpu_switchto)
832f5df1827Smickey	pushq	%rbx
833f5df1827Smickey	pushq	%rbp
834f5df1827Smickey	pushq	%r12
835f5df1827Smickey	pushq	%r13
836f5df1827Smickey	pushq	%r14
837f5df1827Smickey	pushq	%r15
838f5df1827Smickey
839fbe53cacSkrw	movq	%rdi, %r13
840fbe53cacSkrw	movq	%rsi, %r12
841fbe53cacSkrw
84260854cb9Sguenther	/* Record new proc. */
843fbe53cacSkrw	movb	$SONPROC,P_STAT(%r12)	# p->p_stat = SONPROC
844fbe53cacSkrw	SET_CURPROC(%r12,%rcx)
84560854cb9Sguenther
846fd94711fSguenther	movl	CPUVAR(CPUID),%edi
847fd94711fSguenther
848fbe53cacSkrw	/* If old proc exited, don't bother. */
849fbe53cacSkrw	testq	%r13,%r13
850f5df1827Smickey	jz	switch_exited
851f5df1827Smickey
852fbe53cacSkrw	/*
853fbe53cacSkrw	 * Save old context.
854fbe53cacSkrw	 *
855fbe53cacSkrw	 * Registers:
856fbe53cacSkrw	 *   %rax, %rcx - scratch
857fbe53cacSkrw	 *   %r13 - old proc, then old pcb
858fbe53cacSkrw	 *   %r12 - new proc
859fd94711fSguenther	 *   %edi - cpuid
860fbe53cacSkrw	 */
861fbe53cacSkrw
862fbe53cacSkrw	movq	P_ADDR(%r13),%r13
863fbe53cacSkrw
864fd94711fSguenther	/* clear the old pmap's bit for the cpu */
865fd94711fSguenther	movq	PCB_PMAP(%r13),%rcx
866fd94711fSguenther	lock
867f5e1db71Sguenther	btrq	%rdi,PM_CPUS(%rcx)
868fd94711fSguenther
869f5df1827Smickey	/* Save stack pointers. */
870f5df1827Smickey	movq	%rsp,PCB_RSP(%r13)
871f5df1827Smickey	movq	%rbp,PCB_RBP(%r13)
872fbe53cacSkrw
873f5df1827Smickeyswitch_exited:
874b13138f2Sguenther	/* did old proc run in userspace?  then reset the segment regs */
875b13138f2Sguenther	btrl	$CPUF_USERSEGS_BIT, CPUVAR(FLAGS)
876b13138f2Sguenther	jnc	restore_saved
877b13138f2Sguenther
878b13138f2Sguenther	/* set %ds, %es, and %fs to expected value to prevent info leak */
879b13138f2Sguenther	movw	$(GSEL(GUDATA_SEL, SEL_UPL)),%ax
880b13138f2Sguenther	movw	%ax,%ds
881b13138f2Sguenther	movw	%ax,%es
882b13138f2Sguenther	movw	%ax,%fs
883b13138f2Sguenther
884b13138f2Sguentherrestore_saved:
885f5df1827Smickey	/*
88645053f4aSart	 * Restore saved context.
887f5df1827Smickey	 *
888f5df1827Smickey	 * Registers:
889f5df1827Smickey	 *   %rax, %rcx, %rdx - scratch
890f5df1827Smickey	 *   %r13 - new pcb
891fbe53cacSkrw	 *   %r12 - new process
892f5df1827Smickey	 */
893f5df1827Smickey
894fbe53cacSkrw	/* No interrupts while loading new state. */
895fbe53cacSkrw	cli
896fbe53cacSkrw	movq	P_ADDR(%r12),%r13
897fbe53cacSkrw
898f5df1827Smickey	/* Restore stack pointers. */
899f5df1827Smickey	movq	PCB_RSP(%r13),%rsp
900f5df1827Smickey	movq	PCB_RBP(%r13),%rbp
901f5df1827Smickey
902fd94711fSguenther	movq	CPUVAR(TSS),%rcx
903fd94711fSguenther	movq	PCB_KSTACK(%r13),%rdx
904fd94711fSguenther	movq	%rdx,TSS_RSP0(%rcx)
905fd94711fSguenther
906fd94711fSguenther	movq	PCB_CR3(%r13),%rax
907fd94711fSguenther	movq	%rax,%cr3
908fd94711fSguenther
909fbe53cacSkrw	/* Don't bother with the rest if switching to a system process. */
910fbe53cacSkrw	testl	$P_SYSTEM,P_FLAG(%r12)
911fbe53cacSkrw	jnz	switch_restored
912fd94711fSguenther
913fd94711fSguenther	/* set the new pmap's bit for the cpu */
914fd94711fSguenther	movl	CPUVAR(CPUID),%edi
915fd94711fSguenther	movq	PCB_PMAP(%r13),%rcx
916fd94711fSguenther	lock
917f5e1db71Sguenther	btsq	%rdi,PM_CPUS(%rcx)
918fd94711fSguenther#ifdef DIAGNOSTIC
919fd94711fSguenther	jc	_C_LABEL(switch_pmcpu_set)
920fbe53cacSkrw#endif
921f5df1827Smickey
922fbe53cacSkrwswitch_restored:
923f5df1827Smickey	/* Restore cr0 (including FPU state). */
924f5df1827Smickey	movl	PCB_CR0(%r13),%ecx
925f5df1827Smickey#ifdef MULTIPROCESSOR
926f5df1827Smickey	movq	PCB_FPCPU(%r13),%r8
927f5df1827Smickey	cmpq	CPUVAR(SELF),%r8
928f5df1827Smickey	jz	1f
929f5df1827Smickey	orl	$CR0_TS,%ecx
930f5df1827Smickey1:
931f5df1827Smickey#endif
932f5df1827Smickey	movq	%rcx,%cr0
933f5df1827Smickey
934fbe53cacSkrw	SET_CURPCB(%r13)
935fbe53cacSkrw
936f5df1827Smickey	/* Interrupts are okay again. */
937f5df1827Smickey	sti
938f5df1827Smickey
939fbe53cacSkrwswitch_return:
940fbe53cacSkrw
941f5df1827Smickey	popq	%r15
942f5df1827Smickey	popq	%r14
943f5df1827Smickey	popq	%r13
944f5df1827Smickey	popq	%r12
945f5df1827Smickey	popq	%rbp
946f5df1827Smickey	popq	%rbx
947f5df1827Smickey	ret
948f5df1827Smickey
94945053f4aSartENTRY(cpu_idle_enter)
9502692ace4Sjordan	movq	_C_LABEL(cpu_idle_enter_fcn),%rax
9512692ace4Sjordan	cmpq	$0,%rax
9522692ace4Sjordan	je	1f
9532692ace4Sjordan	jmpq	*%rax
9542692ace4Sjordan1:
95545053f4aSart	ret
956f5df1827Smickey
95745053f4aSartENTRY(cpu_idle_cycle)
9582692ace4Sjordan	movq	_C_LABEL(cpu_idle_cycle_fcn),%rax
9592692ace4Sjordan	cmpq	$0,%rax
9602692ace4Sjordan	je	1f
9612692ace4Sjordan	call	*%rax
9622692ace4Sjordan	ret
9632692ace4Sjordan1:
9642692ace4Sjordan	sti
96545053f4aSart	hlt
96645053f4aSart	ret
967f5df1827Smickey
96845053f4aSartENTRY(cpu_idle_leave)
9692692ace4Sjordan	movq	_C_LABEL(cpu_idle_leave_fcn),%rax
9702692ace4Sjordan	cmpq	$0,%rax
9712692ace4Sjordan	je	1f
9722692ace4Sjordan	jmpq	*%rax
9732692ace4Sjordan1:
97445053f4aSart	ret
975f5df1827Smickey
976da4ea94cSart	.globl	_C_LABEL(panic)
977da4ea94cSart
978da4ea94cSart#ifdef DIAGNOSTIC
979fd94711fSguentherNENTRY(switch_pmcpu_set)
980fd94711fSguenther	movabsq	$1f,%rdi
981fd94711fSguenther	call	_C_LABEL(panic)
982fd94711fSguenther	/* NOTREACHED */
983fd94711fSguenther1:	.asciz	"activate already active pmap"
984da4ea94cSart#endif /* DIAGNOSTIC */
985f5df1827Smickey
986f5df1827Smickey/*
987f5df1827Smickey * savectx(struct pcb *pcb);
988f5df1827Smickey * Update pcb, saving current processor state.
989f5df1827Smickey */
990f5df1827SmickeyENTRY(savectx)
991f5df1827Smickey	/* Save stack pointers. */
992f5df1827Smickey	movq	%rsp,PCB_RSP(%rdi)
993f5df1827Smickey	movq	%rbp,PCB_RBP(%rdi)
994f5df1827Smickey
995f5df1827Smickey	ret
996f5df1827Smickey
997f5df1827SmickeyIDTVEC(syscall32)
998f5df1827Smickey	sysret		/* go away please */
999f5df1827Smickey
1000f5df1827Smickey/*
1001f5df1827Smickey * syscall insn entry. This currently isn't much faster, but
1002f5df1827Smickey * it can be made faster in the future.
1003f5df1827Smickey */
1004f5df1827SmickeyIDTVEC(syscall)
100574ebaa6aSguenther	/*
100674ebaa6aSguenther	 * Enter here with interrupts blocked; %rcx contains the caller's
100774ebaa6aSguenther	 * %rip and the original rflags has been copied to %r11.  %cs and
100874ebaa6aSguenther	 * %ss have been updated to the kernel segments, but %rsp is still
100974ebaa6aSguenther	 * the user-space value.
101074ebaa6aSguenther	 * First order of business is to swap to the kernel gs.base so that
101174ebaa6aSguenther	 * we can access our struct cpu_info and use the scratch space there
101274ebaa6aSguenther	 * to switch to our kernel stack.  Once that's in place we can
101374ebaa6aSguenther	 * unblock interrupts and save the rest of the syscall frame.
101474ebaa6aSguenther	 */
1015f5df1827Smickey	swapgs
1016f5df1827Smickey	movq	%r15,CPUVAR(SCRATCH)
1017f5df1827Smickey	movq	CPUVAR(CURPCB),%r15
1018fd94711fSguenther	movq	PCB_KSTACK(%r15),%r15
1019f5df1827Smickey	xchgq	%r15,%rsp
1020f5df1827Smickey	sti
1021f5df1827Smickey
1022f5df1827Smickey	/*
1023f5df1827Smickey	 * XXX don't need this whole frame, split of the
1024f5df1827Smickey	 * syscall frame and trapframe is needed.
1025f5df1827Smickey	 * First, leave some room for the trapno, error,
1026f5df1827Smickey	 * ss:rsp, etc, so that all GP registers can be
1027f5df1827Smickey	 * saved. Then, fill in the rest.
1028f5df1827Smickey	 */
10291f7e6433Sguenther	pushq	$(GSEL(GUDATA_SEL, SEL_UPL))
1030f5df1827Smickey	pushq	%r15
1031f5df1827Smickey	subq	$(TF_RSP-TF_TRAPNO),%rsp
1032f5df1827Smickey	movq	CPUVAR(SCRATCH),%r15
1033f5df1827Smickey	subq	$32,%rsp
1034f5df1827Smickey	INTR_SAVE_GPRS
1035f5df1827Smickey	movq	%r11, TF_RFLAGS(%rsp)	/* old rflags from syscall insn */
10361f7e6433Sguenther	movq	$(GSEL(GUCODE_SEL, SEL_UPL)), TF_CS(%rsp)
1037f5df1827Smickey	movq	%rcx,TF_RIP(%rsp)
10386620a6fbSguenther	movq	$2,TF_ERR(%rsp)		/* ignored */
1039f5df1827Smickey
1040f5df1827Smickey	movq	CPUVAR(CURPROC),%r14
1041f5df1827Smickey	movq	%rsp,P_MD_REGS(%r14)	# save pointer to frame
1042f5df1827Smickey	andl	$~MDP_IRET,P_MD_FLAGS(%r14)
1043b5b9857bSart	movq	%rsp,%rdi
10444e1a77ceSsturm	call	_C_LABEL(syscall)
1045c9ad316fSguenther
1046c9ad316fSguenther.Lsyscall_check_asts:
1047c9ad316fSguenther	/* Check for ASTs on exit to user mode. */
1048f5df1827Smickey	cli
1049f5df1827Smickey	CHECK_ASTPENDING(%r11)
1050f5df1827Smickey	je	2f
1051f5df1827Smickey	CLEAR_ASTPENDING(%r11)
1052f5df1827Smickey	sti
1053b5b9857bSart	movq	%rsp,%rdi
1054c9ad316fSguenther	call	_C_LABEL(ast)
1055c9ad316fSguenther	jmp	.Lsyscall_check_asts
1056c9ad316fSguenther
1057f5df1827Smickey2:
1058f5df1827Smickey#ifdef DIAGNOSTIC
1059b5b9857bSart	cmpl	$IPL_NONE,CPUVAR(ILEVEL)
1060c9ad316fSguenther	jne	.Lsyscall_spl_not_lowered
10611396572dSguenther#endif /* DIAGNOSTIC */
10621396572dSguenther
1063c9ad316fSguenther	/* Could registers have been changed that require an iretq? */
1064c9ad316fSguenther	testl	$MDP_IRET, P_MD_FLAGS(%r14)
1065c9ad316fSguenther	jne	intr_fast_exit
1066c9ad316fSguenther
10671396572dSguenther	movq	TF_RDI(%rsp),%rdi
10681396572dSguenther	movq	TF_RSI(%rsp),%rsi
10691396572dSguenther	movq	TF_R8(%rsp),%r8
10701396572dSguenther	movq	TF_R9(%rsp),%r9
10711396572dSguenther	movq	TF_R10(%rsp),%r10
10721396572dSguenther	movq	TF_R12(%rsp),%r12
10731396572dSguenther	movq	TF_R13(%rsp),%r13
10741396572dSguenther	movq	TF_R14(%rsp),%r14
10751396572dSguenther	movq	TF_R15(%rsp),%r15
10761396572dSguenther	movq	TF_RBP(%rsp),%rbp
10771396572dSguenther	movq	TF_RBX(%rsp),%rbx
10781396572dSguenther
1079f1665d79Sguenther	INTR_RESTORE_SELECTORS
10801396572dSguenther
10811396572dSguenther	movq	TF_RDX(%rsp),%rdx
10821396572dSguenther	movq	TF_RAX(%rsp),%rax
10831396572dSguenther
10841396572dSguenther	movq	TF_RIP(%rsp),%rcx
10851396572dSguenther	movq	TF_RFLAGS(%rsp),%r11
10861396572dSguenther	movq	TF_RSP(%rsp),%rsp
1087f5df1827Smickey	sysretq
1088f5df1827Smickey
1089f5df1827Smickey#ifdef DIAGNOSTIC
1090c9ad316fSguenther.Lsyscall_spl_not_lowered:
1091c9ad316fSguenther	movabsq	$4f, %rdi
1092f5df1827Smickey	movl	TF_RAX(%rsp),%esi
1093f5df1827Smickey	movl	TF_RDI(%rsp),%edx
1094f5df1827Smickey	movl	%ebx,%ecx
1095b5b9857bSart	movl	CPUVAR(ILEVEL),%r8d
1096f5df1827Smickey	xorq	%rax,%rax
1097f5df1827Smickey	call	_C_LABEL(printf)
1098f5df1827Smickey#ifdef DDB
1099f5df1827Smickey	int	$3
1100f5df1827Smickey#endif /* DDB */
1101f5df1827Smickey	movl	$IPL_NONE,CPUVAR(ILEVEL)
1102c9ad316fSguenther	jmp	.Lsyscall_check_asts
1103f5df1827Smickey4:	.asciz	"WARNING: SPL NOT LOWERED ON SYSCALL %d %d EXIT %x %x\n"
1104f5df1827Smickey#endif
1105f5df1827Smickey
1106f5df1827Smickey
1107f5df1827SmickeyNENTRY(proc_trampoline)
1108f5df1827Smickey#ifdef MULTIPROCESSOR
1109f5df1827Smickey	call	_C_LABEL(proc_trampoline_mp)
1110f5df1827Smickey#endif
1111f5df1827Smickey	movl	$IPL_NONE,CPUVAR(ILEVEL)
1112f5df1827Smickey	movq	%r13,%rdi
1113f5df1827Smickey	call	*%r12
1114c9ad316fSguenther	movq	CPUVAR(CURPROC),%r14
1115c9ad316fSguenther	jmp	.Lsyscall_check_asts
1116f5df1827Smickey
1117f5df1827Smickey
1118f5df1827Smickey/*
11191396572dSguenther * Return via iretq, for real interrupts and signal returns
11201396572dSguenther */
1121c9ad316fSguentherNENTRY(intr_fast_exit)
11221396572dSguenther	movq	TF_RDI(%rsp),%rdi
11231396572dSguenther	movq	TF_RSI(%rsp),%rsi
11241396572dSguenther	movq	TF_R8(%rsp),%r8
11251396572dSguenther	movq	TF_R9(%rsp),%r9
11261396572dSguenther	movq	TF_R10(%rsp),%r10
11271396572dSguenther	movq	TF_R12(%rsp),%r12
11281396572dSguenther	movq	TF_R13(%rsp),%r13
11291396572dSguenther	movq	TF_R14(%rsp),%r14
11301396572dSguenther	movq	TF_R15(%rsp),%r15
11311396572dSguenther	movq	TF_RBP(%rsp),%rbp
11321396572dSguenther	movq	TF_RBX(%rsp),%rbx
11331396572dSguenther
113492f33f2bSguenther	testq	$SEL_RPL,TF_CS(%rsp)
1135c6853312Sguenther	je	5f
11361396572dSguenther
1137f1665d79Sguenther	INTR_RESTORE_SELECTORS
11381396572dSguenther
11391396572dSguenther5:	movq	TF_RDX(%rsp),%rdx
11401396572dSguenther	movq	TF_RCX(%rsp),%rcx
11411396572dSguenther	movq	TF_R11(%rsp),%r11
11421396572dSguenther	movq	TF_RAX(%rsp),%rax
11431396572dSguenther	addq	$TF_RIP,%rsp
11441396572dSguenther
1145c6853312Sguenther	.globl	_C_LABEL(doreti_iret)
1146c6853312Sguenther_C_LABEL(doreti_iret):
1147c6853312Sguenther	iretq
1148c6853312Sguenther
11493a36161cSart
11503a36161cSartENTRY(pagezero)
11513a36161cSart	movq    $-PAGE_SIZE,%rdx
11523a36161cSart	subq    %rdx,%rdi
11533a36161cSart	xorq    %rax,%rax
11543a36161cSart1:
11553a36161cSart	movnti  %rax,(%rdi,%rdx)
11563a36161cSart	movnti  %rax,8(%rdi,%rdx)
11573a36161cSart	movnti  %rax,16(%rdi,%rdx)
11583a36161cSart	movnti  %rax,24(%rdi,%rdx)
11593a36161cSart	addq    $32,%rdx
11603a36161cSart	jne     1b
11613a36161cSart	sfence
11623a36161cSart	ret
11633c8478a6Sgwk
116461d6df42Ssf	.section .codepatch,"a"
116561d6df42Ssf	.align  8
116661d6df42Ssf	.globl _C_LABEL(codepatch_begin)
116761d6df42Ssf_C_LABEL(codepatch_begin):
116861d6df42Ssf	.previous
116961d6df42Ssf
117061d6df42Ssf	.section .codepatchend,"a"
117161d6df42Ssf	.globl _C_LABEL(codepatch_end)
117261d6df42Ssf_C_LABEL(codepatch_end):
117361d6df42Ssf	.previous
1174