1b5b9857bSart/* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ 2f5df1827Smickey 3f5df1827Smickey/* 4f5df1827Smickey * Copyright-o-rama! 5f5df1827Smickey */ 6f5df1827Smickey 7f5df1827Smickey/* 8f5df1827Smickey * Copyright (c) 2001 Wasabi Systems, Inc. 9f5df1827Smickey * All rights reserved. 10f5df1827Smickey * 11f5df1827Smickey * Written by Frank van der Linden for Wasabi Systems, Inc. 12f5df1827Smickey * 13f5df1827Smickey * Redistribution and use in source and binary forms, with or without 14f5df1827Smickey * modification, are permitted provided that the following conditions 15f5df1827Smickey * are met: 16f5df1827Smickey * 1. Redistributions of source code must retain the above copyright 17f5df1827Smickey * notice, this list of conditions and the following disclaimer. 18f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright 19f5df1827Smickey * notice, this list of conditions and the following disclaimer in the 20f5df1827Smickey * documentation and/or other materials provided with the distribution. 21f5df1827Smickey * 3. All advertising materials mentioning features or use of this software 22f5df1827Smickey * must display the following acknowledgement: 23f5df1827Smickey * This product includes software developed for the NetBSD Project by 24f5df1827Smickey * Wasabi Systems, Inc. 25f5df1827Smickey * 4. The name of Wasabi Systems, Inc. may not be used to endorse 26f5df1827Smickey * or promote products derived from this software without specific prior 27f5df1827Smickey * written permission. 28f5df1827Smickey * 29f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 30f5df1827Smickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31f5df1827Smickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32f5df1827Smickey * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 33f5df1827Smickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34f5df1827Smickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35f5df1827Smickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36f5df1827Smickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37f5df1827Smickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38f5df1827Smickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39f5df1827Smickey * POSSIBILITY OF SUCH DAMAGE. 40f5df1827Smickey */ 41f5df1827Smickey 42f5df1827Smickey 43f5df1827Smickey/*- 44f5df1827Smickey * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 45f5df1827Smickey * All rights reserved. 46f5df1827Smickey * 47f5df1827Smickey * This code is derived from software contributed to The NetBSD Foundation 48f5df1827Smickey * by Charles M. Hannum. 49f5df1827Smickey * 50f5df1827Smickey * Redistribution and use in source and binary forms, with or without 51f5df1827Smickey * modification, are permitted provided that the following conditions 52f5df1827Smickey * are met: 53f5df1827Smickey * 1. Redistributions of source code must retain the above copyright 54f5df1827Smickey * notice, this list of conditions and the following disclaimer. 55f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright 56f5df1827Smickey * notice, this list of conditions and the following disclaimer in the 57f5df1827Smickey * documentation and/or other materials provided with the distribution. 58f5df1827Smickey * 3. All advertising materials mentioning features or use of this software 59f5df1827Smickey * must display the following acknowledgement: 60f5df1827Smickey * This product includes software developed by the NetBSD 61f5df1827Smickey * Foundation, Inc. and its contributors. 62f5df1827Smickey * 4. Neither the name of The NetBSD Foundation nor the names of its 63f5df1827Smickey * contributors may be used to endorse or promote products derived 64f5df1827Smickey * from this software without specific prior written permission. 65f5df1827Smickey * 66f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 67f5df1827Smickey * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 68f5df1827Smickey * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 69f5df1827Smickey * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 70f5df1827Smickey * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 71f5df1827Smickey * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 72f5df1827Smickey * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 73f5df1827Smickey * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 74f5df1827Smickey * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 75f5df1827Smickey * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 76f5df1827Smickey * POSSIBILITY OF SUCH DAMAGE. 77f5df1827Smickey */ 78f5df1827Smickey 79f5df1827Smickey/*- 80f5df1827Smickey * Copyright (c) 1990 The Regents of the University of California. 81f5df1827Smickey * All rights reserved. 82f5df1827Smickey * 83f5df1827Smickey * This code is derived from software contributed to Berkeley by 84f5df1827Smickey * William Jolitz. 85f5df1827Smickey * 86f5df1827Smickey * Redistribution and use in source and binary forms, with or without 87f5df1827Smickey * modification, are permitted provided that the following conditions 88f5df1827Smickey * are met: 89f5df1827Smickey * 1. Redistributions of source code must retain the above copyright 90f5df1827Smickey * notice, this list of conditions and the following disclaimer. 91f5df1827Smickey * 2. Redistributions in binary form must reproduce the above copyright 92f5df1827Smickey * notice, this list of conditions and the following disclaimer in the 93f5df1827Smickey * documentation and/or other materials provided with the distribution. 94b5b9857bSart * 3. Neither the name of the University nor the names of its contributors 95f5df1827Smickey * may be used to endorse or promote products derived from this software 96f5df1827Smickey * without specific prior written permission. 97f5df1827Smickey * 98f5df1827Smickey * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 99f5df1827Smickey * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 100f5df1827Smickey * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 101f5df1827Smickey * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 102f5df1827Smickey * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 103f5df1827Smickey * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 104f5df1827Smickey * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 105f5df1827Smickey * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 106f5df1827Smickey * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 107f5df1827Smickey * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 108f5df1827Smickey * SUCH DAMAGE. 109f5df1827Smickey * 110f5df1827Smickey * @(#)locore.s 7.3 (Berkeley) 5/13/91 111f5df1827Smickey */ 112f5df1827Smickey 113f5df1827Smickey#include "assym.h" 114f5df1827Smickey#include "lapic.h" 115f5df1827Smickey#include "ioapic.h" 116f5df1827Smickey#include "ksyms.h" 117f5df1827Smickey 118f5df1827Smickey#include <sys/errno.h> 119f5df1827Smickey#include <sys/syscall.h> 120f5df1827Smickey 121f5df1827Smickey#include <machine/param.h> 122f5df1827Smickey#include <machine/segments.h> 123f5df1827Smickey#include <machine/specialreg.h> 124f5df1827Smickey#include <machine/trap.h> 125f5df1827Smickey#include <machine/frameasm.h> 126f5df1827Smickey 127f5df1827Smickey#if NLAPIC > 0 128f5df1827Smickey#include <machine/i82489reg.h> 129f5df1827Smickey#endif 130f5df1827Smickey 131f5df1827Smickey/* 132f5df1827Smickey * override user-land alignment before including asm.h 133f5df1827Smickey */ 134f5df1827Smickey#define ALIGN_DATA .align 8 135f5df1827Smickey#define ALIGN_TEXT .align 16,0x90 136f5df1827Smickey#define _ALIGN_TEXT ALIGN_TEXT 137f5df1827Smickey 138f5df1827Smickey#include <machine/asm.h> 139f5df1827Smickey 140f5df1827Smickey#define SET_CURPROC(proc,cpu) \ 141f5df1827Smickey movq CPUVAR(SELF),cpu ; \ 142f5df1827Smickey movq proc,CPUVAR(CURPROC) ; \ 143f5df1827Smickey movq cpu,P_CPU(proc) 144f5df1827Smickey 145f5df1827Smickey#define GET_CURPCB(reg) movq CPUVAR(CURPCB),reg 146f5df1827Smickey#define SET_CURPCB(reg) movq reg,CPUVAR(CURPCB) 147f5df1827Smickey 148f5df1827Smickey 149f5df1827Smickey/* XXX temporary kluge; these should not be here */ 150f5df1827Smickey/* Get definitions for IOM_BEGIN, IOM_END, and IOM_SIZE */ 151f5df1827Smickey#include <dev/isa/isareg.h> 152f5df1827Smickey 153f5df1827Smickey 154f5df1827Smickey/* 155f5df1827Smickey * Initialization 156f5df1827Smickey */ 157f5df1827Smickey .data 158f5df1827Smickey 159f5df1827Smickey#if NLAPIC > 0 160f5df1827Smickey .align NBPG 161f5df1827Smickey .globl _C_LABEL(local_apic), _C_LABEL(lapic_id), _C_LABEL(lapic_tpr) 162f5df1827Smickey_C_LABEL(local_apic): 163f5df1827Smickey .space LAPIC_ID 164f5df1827Smickey_C_LABEL(lapic_id): 165f5df1827Smickey .long 0x00000000 166f5df1827Smickey .space LAPIC_TPRI-(LAPIC_ID+4) 167f5df1827Smickey_C_LABEL(lapic_tpr): 168f5df1827Smickey .space LAPIC_PPRI-LAPIC_TPRI 169f5df1827Smickey_C_LABEL(lapic_ppr): 170f5df1827Smickey .space LAPIC_ISR-LAPIC_PPRI 171f5df1827Smickey_C_LABEL(lapic_isr): 172f5df1827Smickey .space NBPG-LAPIC_ISR 173f5df1827Smickey#endif 174f5df1827Smickey 175f5df1827Smickey .globl _C_LABEL(cpu_id),_C_LABEL(cpu_vendor), _C_LABEL(cpu_brand_id) 176f5df1827Smickey .globl _C_LABEL(cpuid_level),_C_LABEL(cpu_feature) 177a47f7207Smickey .globl _C_LABEL(esym),_C_LABEL(boothowto),_C_LABEL(bootdev) 1786483bf47Sderaadt .globl _C_LABEL(bootinfo), _C_LABEL(bootinfo_size), _C_LABEL(atdevbase) 179f5df1827Smickey .globl _C_LABEL(proc0paddr),_C_LABEL(PTDpaddr) 180f5df1827Smickey .globl _C_LABEL(biosbasemem),_C_LABEL(biosextmem) 1816483bf47Sderaadt .globl _C_LABEL(bootapiver) 182f5df1827Smickey_C_LABEL(cpu): .long 0 # are we 386, 386sx, or 486, 183f5df1827Smickey # or Pentium, or.. 184f5df1827Smickey_C_LABEL(cpu_id): .long 0 # saved from `cpuid' instruction 185f5df1827Smickey_C_LABEL(cpu_feature): .long 0 # feature flags from 'cpuid' 186f5df1827Smickey # instruction 187f5df1827Smickey_C_LABEL(cpuid_level): .long -1 # max. level accepted by 'cpuid' 188f5df1827Smickey # instruction 189f5df1827Smickey_C_LABEL(cpu_vendor): .space 16 # vendor string returned by `cpuid' 190f5df1827Smickey # instruction 191f5df1827Smickey_C_LABEL(cpu_brand_id): .long 0 # brand ID from 'cpuid' instruction 192f5df1827Smickey_C_LABEL(esym): .quad 0 # ptr to end of syms 193f5df1827Smickey_C_LABEL(atdevbase): .quad 0 # location of start of iomem in virtual 194e9dacf7aStom_C_LABEL(bootapiver): .long 0 # /boot API version 195*f431e893Smillert_C_LABEL(bootdev): .long 0 # device we booted from 196f5df1827Smickey_C_LABEL(proc0paddr): .quad 0 197f5df1827Smickey_C_LABEL(PTDpaddr): .quad 0 # paddr of PTD, for libkvm 198f5df1827Smickey#ifndef REALBASEMEM 199f5df1827Smickey_C_LABEL(biosbasemem): .long 0 # base memory reported by BIOS 200f5df1827Smickey#else 201f5df1827Smickey_C_LABEL(biosbasemem): .long REALBASEMEM 202f5df1827Smickey#endif 203f5df1827Smickey#ifndef REALEXTMEM 204f5df1827Smickey_C_LABEL(biosextmem): .long 0 # extended memory reported by BIOS 205f5df1827Smickey#else 206f5df1827Smickey_C_LABEL(biosextmem): .long REALEXTMEM 207f5df1827Smickey#endif 208f5df1827Smickey 209f5df1827Smickey#define _RELOC(x) ((x) - KERNBASE) 210f5df1827Smickey#define RELOC(x) _RELOC(_C_LABEL(x)) 211f5df1827Smickey 212f5df1827Smickey .globl gdt64 213f5df1827Smickey 214f5df1827Smickeygdt64: 215f5df1827Smickey .word gdt64_end-gdt64_start 216f5df1827Smickey .quad _RELOC(gdt64_start) 217f5df1827Smickey.align 64 218f5df1827Smickey 219f5df1827Smickeygdt64_start: 220f5df1827Smickey .quad 0x0000000000000000 /* always empty */ 221f5df1827Smickey .quad 0x00af9a000000ffff /* kernel CS */ 222f5df1827Smickey .quad 0x00cf92000000ffff /* kernel DS */ 223f5df1827Smickeygdt64_end: 224f5df1827Smickey 225f5df1827Smickeyfarjmp64: 226f5df1827Smickey .long longmode-KERNBASE 227f5df1827Smickey .word GSEL(GCODE_SEL, SEL_KPL) 228f5df1827Smickey 229f5df1827Smickey .space 512 230f5df1827Smickeytmpstk: 231f5df1827Smickey 232f5df1827Smickey .globl _C_LABEL(cpu_private) 233f5df1827Smickey .comm _C_LABEL(cpu_private),NBPG,NBPG 234f5df1827Smickey 235f5df1827Smickey/* 236f5df1827Smickey * Some hackage to deal with 64bit symbols in 32 bit mode. 237e9dacf7aStom * This may not be needed if things are cleaned up a little. 238f5df1827Smickey */ 239f5df1827Smickey 240f5df1827Smickey 241f5df1827Smickey .text 242f5df1827Smickey .globl _C_LABEL(kernel_text) 243f5df1827Smickey .set _C_LABEL(kernel_text),KERNTEXTOFF 244f5df1827Smickey 245f5df1827Smickey .code32 246f5df1827Smickey 247f5df1827Smickey .globl start 248f5df1827Smickeystart: movw $0x1234,0x472 # warm boot 249f5df1827Smickey 250f5df1827Smickey /* 251f5df1827Smickey * Load parameters from stack 252930756e7Stom * (howto, bootdev, bootapiver, esym, extmem, cnvmem, ac, av) 253f5df1827Smickey */ 254f5df1827Smickey movl 4(%esp),%eax 255930756e7Stom movl %eax, RELOC(boothowto) 256a47f7207Smickey movl 8(%esp),%eax 257930756e7Stom movl %eax, RELOC(bootdev) 258f5df1827Smickey 259f5df1827Smickey movl 16(%esp), %eax 260f5df1827Smickey testl %eax,%eax 261f5df1827Smickey jz 1f 262f5df1827Smickey addl $KERNBASE_LO,%eax 263a47f7207Smickey movl $RELOC(esym),%ebp 264f5df1827Smickey movl %eax,(%ebp) 265f5df1827Smickey movl $KERNBASE_HI,4(%ebp) 266a47f7207Smickey1: 267f5df1827Smickey movl 20(%esp), %eax 268a47f7207Smickey movl %eax, RELOC(biosextmem) 269f5df1827Smickey movl 24(%esp), %eax 270a47f7207Smickey movl %eax, RELOC(biosbasemem) 271f5df1827Smickey 272e9dacf7aStom movl 12(%esp), %eax 273e9dacf7aStom movl %eax, RELOC(bootapiver) 2746483bf47Sderaadt 2756483bf47Sderaadt /* 2766483bf47Sderaadt * Copy the boot arguments to bootinfo[] in machdep.c. 2776483bf47Sderaadt * 2786483bf47Sderaadt * We are passed the size of bootinfo[] in bootinfo_size, and 2796483bf47Sderaadt * we report how much data /boot passed us back in the same variable. 2806483bf47Sderaadt * 2816483bf47Sderaadt * machdep.c can then take action if bootinfo_size >= bootinfo[] 2826483bf47Sderaadt * (which would meant that we may have been passed too much data). 2836483bf47Sderaadt */ 284e9dacf7aStom movl 28(%esp), %eax 2856483bf47Sderaadt movl %eax, %ecx 2866483bf47Sderaadt cmpl RELOC(bootinfo_size), %ecx /* Too much? */ 2876483bf47Sderaadt jnc bi_size_ok 2886483bf47Sderaadt movl RELOC(bootinfo_size), %ecx /* Only copy this much */ 2896483bf47Sderaadtbi_size_ok: 2906483bf47Sderaadt movl %eax, RELOC(bootinfo_size) /* Report full amount */ 2916483bf47Sderaadt 2926483bf47Sderaadt movl $RELOC(bootinfo), %edi /* Destination */ 2936483bf47Sderaadt movl 32(%esp), %esi /* Source */ 2946483bf47Sderaadt rep movsb /* Copy this many bytes */ 295e9dacf7aStom 296f5df1827Smickey /* First, reset the PSL. */ 297f5df1827Smickey pushl $PSL_MBO 298f5df1827Smickey popfl 299f5df1827Smickey 300f5df1827Smickey xorl %eax,%eax 301f5df1827Smickey cpuid 302f5df1827Smickey movl %eax,RELOC(cpuid_level) 303f5df1827Smickey movl $RELOC(cpu_vendor),%ebp 304f5df1827Smickey movl %ebx,(%ebp) 305f5df1827Smickey movl %edx,4(%ebp) 306f5df1827Smickey movl %ecx,8(%ebp) 307f5df1827Smickey movl $0, 12(%ebp) 308f5df1827Smickey 309f5df1827Smickey movl $1,%eax 310f5df1827Smickey cpuid 311f5df1827Smickey movl %eax,RELOC(cpu_id) 312f5df1827Smickey movl %edx,RELOC(cpu_feature) 313f5df1827Smickey 3141fef3300Smickey movl $0x80000001, %eax 3151fef3300Smickey cpuid 3161fef3300Smickey andl $CPUID_NXE, %edx /* other bits may clash */ 3171fef3300Smickey orl %edx, RELOC(cpu_feature) 3181fef3300Smickey 319f5df1827Smickey /* Brand ID is bits 0-7 of %ebx */ 320f5df1827Smickey andl $255,%ebx 321f5df1827Smickey movl %ebx,RELOC(cpu_brand_id) 322f5df1827Smickey 323f5df1827Smickey /* 324f5df1827Smickey * Finished with old stack; load new %esp now instead of later so we 325f5df1827Smickey * can trace this code without having to worry about the trace trap 326f5df1827Smickey * clobbering the memory test or the zeroing of the bss+bootstrap page 327f5df1827Smickey * tables. 328f5df1827Smickey * 329f5df1827Smickey * The boot program should check: 330f5df1827Smickey * text+data <= &stack_variable - more_space_for_stack 331f5df1827Smickey * text+data+bss+pad+space_for_page_tables <= end_of_memory 332f5df1827Smickey * Oops, the gdt is in the carcass of the boot program so clearing 333f5df1827Smickey * the rest of memory is still not possible. 334f5df1827Smickey */ 335f5df1827Smickey movl $RELOC(tmpstk),%esp 336f5df1827Smickey 337f5df1827Smickey/* 338f5df1827Smickey * Virtual address space of kernel: 339f5df1827Smickey * 340f5df1827Smickey * text | data | bss | [syms] | page dir | proc0 kstack | L1 ptp | L2 ptp | L3 341f5df1827Smickey * 0 1 2 3 342f5df1827Smickey */ 343f5df1827Smickey 344f5df1827Smickey#if L2_SLOT_KERNBASE > 0 345f5df1827Smickey#define TABLE_L2_ENTRIES (2 * (NKL2_KIMG_ENTRIES + 1)) 346f5df1827Smickey#else 347f5df1827Smickey#define TABLE_L2_ENTRIES (NKL2_KIMG_ENTRIES + 1) 348f5df1827Smickey#endif 349f5df1827Smickey 350f5df1827Smickey#if L3_SLOT_KERNBASE > 0 351f5df1827Smickey#define TABLE_L3_ENTRIES (2 * NKL3_KIMG_ENTRIES) 352f5df1827Smickey#else 353f5df1827Smickey#define TABLE_L3_ENTRIES NKL3_KIMG_ENTRIES 354f5df1827Smickey#endif 355f5df1827Smickey 356f5df1827Smickey 357f5df1827Smickey#define PROC0_PML4_OFF 0 358f5df1827Smickey#define PROC0_STK_OFF (PROC0_PML4_OFF + NBPG) 359f5df1827Smickey#define PROC0_PTP3_OFF (PROC0_STK_OFF + UPAGES * NBPG) 360f5df1827Smickey#define PROC0_PTP2_OFF (PROC0_PTP3_OFF + NKL4_KIMG_ENTRIES * NBPG) 361f5df1827Smickey#define PROC0_PTP1_OFF (PROC0_PTP2_OFF + TABLE_L3_ENTRIES * NBPG) 362f5df1827Smickey#define TABLESIZE \ 363f5df1827Smickey ((NKL4_KIMG_ENTRIES + TABLE_L3_ENTRIES + TABLE_L2_ENTRIES + 1 + UPAGES) \ 364f5df1827Smickey * NBPG) 365f5df1827Smickey 366f5df1827Smickey#define fillkpt \ 367f5df1827Smickey1: movl %eax,(%ebx) ; /* store phys addr */ \ 368f5df1827Smickey movl $0,4(%ebx) ; /* upper 32 bits 0 */ \ 369f5df1827Smickey addl $8,%ebx ; /* next pte/pde */ \ 370f5df1827Smickey addl $NBPG,%eax ; /* next phys page */ \ 371f5df1827Smickey loop 1b ; \ 372f5df1827Smickey 373f5df1827Smickey 374f5df1827Smickey /* Find end of kernel image. */ 375f5df1827Smickey movl $RELOC(end),%edi 376f5df1827Smickey#if (NKSYMS || defined(DDB) || defined(LKM)) && !defined(SYMTAB_SPACE) 377f5df1827Smickey /* Save the symbols (if loaded). */ 378f5df1827Smickey movl RELOC(esym),%eax 379f5df1827Smickey testl %eax,%eax 380f5df1827Smickey jz 1f 381f5df1827Smickey subl $KERNBASE_LO,%eax /* XXX */ 382f5df1827Smickey movl %eax,%edi 383f5df1827Smickey1: 384f5df1827Smickey#endif 385f5df1827Smickey /* Clear tables */ 386f5df1827Smickey movl %edi,%esi 387f5df1827Smickey addl $PGOFSET,%esi 388f5df1827Smickey andl $~PGOFSET,%esi 389f5df1827Smickey 390f5df1827Smickey movl %esi,%edi 391f5df1827Smickey xorl %eax,%eax 392f5df1827Smickey cld 393f5df1827Smickey movl $TABLESIZE,%ecx 394f5df1827Smickey shrl $2,%ecx 395f5df1827Smickey rep 396f5df1827Smickey stosl 397f5df1827Smickey 398f5df1827Smickey leal (PROC0_PTP1_OFF)(%esi), %ebx 399f5df1827Smickey 400f5df1827Smickey /* 401f5df1827Smickey * Compute etext - KERNBASE. This can't be > 4G, or we can't deal 402f5df1827Smickey * with it anyway, since we can't load it in 32 bit mode. So use 403f5df1827Smickey * the bottom 32 bits. 404f5df1827Smickey */ 405f5df1827Smickey movl $RELOC(etext),%edx 406f5df1827Smickey addl $PGOFSET,%edx 407f5df1827Smickey andl $~PGOFSET,%edx 408f5df1827Smickey 409f5df1827Smickey /* 410f5df1827Smickey * Skip the first MB. 411f5df1827Smickey */ 412f5df1827Smickey movl $(KERNTEXTOFF_LO - KERNBASE_LO),%eax 413f5df1827Smickey movl %eax,%ecx 414f5df1827Smickey shrl $(PGSHIFT-3),%ecx /* ((n >> PGSHIFT) << 3) for # pdes */ 415f5df1827Smickey addl %ecx,%ebx 416f5df1827Smickey 417f5df1827Smickey /* Map kernel text read-only */ 418f5df1827Smickey movl %edx,%ecx 419f5df1827Smickey subl %eax,%ecx 420f5df1827Smickey shrl $PGSHIFT,%ecx 421f5df1827Smickey orl $(PG_V|PG_KR),%eax 422f5df1827Smickey fillkpt 423f5df1827Smickey 424f5df1827Smickey /* Map the data, BSS, and bootstrap tables read-write. */ 425f5df1827Smickey leal (PG_V|PG_KW)(%edx),%eax 426f5df1827Smickey movl $TABLESIZE,%ecx 427f5df1827Smickey addl %esi,%ecx /* %ecx = &end[TABLESIZE] */ 428f5df1827Smickey subl %edx,%ecx /* %ecx = %ecx - etext */ 429f5df1827Smickey shrl $PGSHIFT,%ecx 430f5df1827Smickey fillkpt 431f5df1827Smickey 432f5df1827Smickey /* Map ISA I/O mem (later atdevbase) */ 433f5df1827Smickey movl $(IOM_BEGIN|PG_V|PG_KW/*|PG_N*/),%eax 434f5df1827Smickey movl $(IOM_SIZE>>PGSHIFT),%ecx 435f5df1827Smickey fillkpt 436f5df1827Smickey 437f5df1827Smickey /* Set up level 2 pages */ 438f5df1827Smickey leal (PROC0_PTP2_OFF)(%esi),%ebx 439f5df1827Smickey leal (PROC0_PTP1_OFF)(%esi),%eax 440f5df1827Smickey orl $(PG_V|PG_KW), %eax 441f5df1827Smickey movl $(NKL2_KIMG_ENTRIES+1),%ecx 442f5df1827Smickey fillkpt 443f5df1827Smickey 444f5df1827Smickey#if L2_SLOT_KERNBASE > 0 445f5df1827Smickey /* If needed, set up level 2 entries for actual kernel mapping */ 446f5df1827Smickey leal (PROC0_PTP2_OFF+ L2_SLOT_KERNBASE*8)(%esi),%ebx 447f5df1827Smickey leal (PROC0_PTP1_OFF)(%esi),%eax 448f5df1827Smickey orl $(PG_V|PG_KW), %eax 449f5df1827Smickey movl $(NKL2_KIMG_ENTRIES+1),%ecx 450f5df1827Smickey fillkpt 451f5df1827Smickey#endif 452f5df1827Smickey 453f5df1827Smickey /* Set up level 3 pages */ 454f5df1827Smickey leal (PROC0_PTP3_OFF)(%esi),%ebx 455f5df1827Smickey leal (PROC0_PTP2_OFF)(%esi),%eax 456f5df1827Smickey orl $(PG_V|PG_KW), %eax 457f5df1827Smickey movl $NKL3_KIMG_ENTRIES,%ecx 458f5df1827Smickey fillkpt 459f5df1827Smickey 460f5df1827Smickey#if L3_SLOT_KERNBASE > 0 461f5df1827Smickey /* If needed, set up level 3 entries for actual kernel mapping */ 462f5df1827Smickey leal (PROC0_PTP3_OFF+ L3_SLOT_KERNBASE*8)(%esi),%ebx 463f5df1827Smickey leal (PROC0_PTP2_OFF)(%esi),%eax 464f5df1827Smickey orl $(PG_V|PG_KW), %eax 465f5df1827Smickey movl $NKL3_KIMG_ENTRIES,%ecx 466f5df1827Smickey fillkpt 467f5df1827Smickey#endif 468f5df1827Smickey 469f5df1827Smickey /* Set up top level entries for identity mapping */ 470f5df1827Smickey leal (PROC0_PML4_OFF)(%esi),%ebx 471f5df1827Smickey leal (PROC0_PTP3_OFF)(%esi),%eax 472f5df1827Smickey orl $(PG_V|PG_KW), %eax 473f5df1827Smickey movl $NKL4_KIMG_ENTRIES,%ecx 474f5df1827Smickey fillkpt 475f5df1827Smickey 476f5df1827Smickey /* Set up top level entries for actual kernel mapping */ 477f5df1827Smickey leal (PROC0_PML4_OFF + L4_SLOT_KERNBASE*8)(%esi),%ebx 478f5df1827Smickey leal (PROC0_PTP3_OFF)(%esi),%eax 479f5df1827Smickey orl $(PG_V|PG_KW), %eax 480f5df1827Smickey movl $NKL4_KIMG_ENTRIES,%ecx 481f5df1827Smickey fillkpt 482f5df1827Smickey 483f5df1827Smickey /* Install recursive top level PDE */ 484f5df1827Smickey leal (PROC0_PML4_OFF + PDIR_SLOT_PTE*8)(%esi),%ebx 485f5df1827Smickey leal (PROC0_PML4_OFF)(%esi),%eax 486f5df1827Smickey orl $(PG_V|PG_KW),%eax 487f5df1827Smickey movl %eax,(%ebx) 488f5df1827Smickey movl $0, 4(%ebx) 489f5df1827Smickey 490f5df1827Smickey 491f5df1827Smickey /* Save phys. addr of PTD, for libkvm. */ 492f5df1827Smickey movl $RELOC(PTDpaddr),%ebp 493f5df1827Smickey movl %esi,(%ebp) 494f5df1827Smickey movl $0,4(%ebp) 495f5df1827Smickey 496f5df1827Smickey /* 497f5df1827Smickey * Startup checklist: 498f5df1827Smickey * 1. Enable PAE (and SSE while here). 499f5df1827Smickey */ 500f5df1827Smickey movl %cr4,%eax 501f5df1827Smickey orl $(CR4_PAE|CR4_OSFXSR|CR4_OSXMMEXCPT),%eax 502f5df1827Smickey movl %eax,%cr4 503f5df1827Smickey 504f5df1827Smickey /* 505f5df1827Smickey * 2. Set Long Mode Enable in EFER. Also enable the 506f5df1827Smickey * syscall extensions. 507f5df1827Smickey */ 508f5df1827Smickey movl $MSR_EFER,%ecx 509f5df1827Smickey rdmsr 510f5df1827Smickey xorl %eax,%eax /* XXX */ 511f5df1827Smickey orl $(EFER_LME|EFER_SCE),%eax 512f5df1827Smickey wrmsr 513f5df1827Smickey 514f5df1827Smickey /* 515f5df1827Smickey * 3. Load %cr3 with pointer to PML4. 516f5df1827Smickey */ 517f5df1827Smickey movl %esi,%eax 518f5df1827Smickey movl %eax,%cr3 519f5df1827Smickey 520f5df1827Smickey /* 521f5df1827Smickey * 4. Enable paging and the rest of it. 522f5df1827Smickey */ 523f5df1827Smickey movl %cr0,%eax 524f5df1827Smickey orl $(CR0_PE|CR0_PG|CR0_NE|CR0_TS|CR0_MP|CR0_WP),%eax 525f5df1827Smickey movl %eax,%cr0 526f5df1827Smickey jmp compat 527f5df1827Smickeycompat: 528f5df1827Smickey 529f5df1827Smickey /* 530f5df1827Smickey * 5. 531f5df1827Smickey * Not quite done yet, we're now in a compatibility segment, 532f5df1827Smickey * in legacy mode. We must jump to a long mode segment. 533f5df1827Smickey * Need to set up a temporary GDT with a long mode segment 534f5df1827Smickey * in it to do that. 535f5df1827Smickey */ 536f5df1827Smickey 537f5df1827Smickey movl $RELOC(gdt64),%eax 538f5df1827Smickey lgdt (%eax) 539f5df1827Smickey movl $RELOC(farjmp64),%eax 540f5df1827Smickey ljmp *(%eax) 541f5df1827Smickey 542f5df1827Smickey.code64 543f5df1827Smickeylongmode: 544f5df1827Smickey /* 545f5df1827Smickey * 6. 546f5df1827Smickey * Finally, we're in long mode. However, we're still 547f5df1827Smickey * in the identity mapped area (could not jump out 548f5df1827Smickey * of that earlier because it would have been a > 32bit 549f5df1827Smickey * jump). We can do that now, so here we go. 550f5df1827Smickey */ 551f5df1827Smickey movabsq $longmode_hi,%rax 552f5df1827Smickey jmp *%rax 553f5df1827Smickeylongmode_hi: 554f5df1827Smickey /* 555f5df1827Smickey * We have arrived. 556f5df1827Smickey * There's no need anymore for the identity mapping in low 557f5df1827Smickey * memory, remove it. 558f5df1827Smickey */ 559f5df1827Smickey movq $KERNBASE,%r8 560f5df1827Smickey 561f5df1827Smickey#if L2_SLOT_KERNBASE > 0 562f5df1827Smickey movq $(NKL2_KIMG_ENTRIES+1),%rcx 563f5df1827Smickey leaq (PROC0_PTP2_OFF)(%rsi),%rbx 564f5df1827Smickey addq %r8, %rbx 565f5df1827Smickey1: movq $0,(%rbx) 566f5df1827Smickey addq $8,%rbx 567f5df1827Smickey loop 1b 568f5df1827Smickey#endif 569f5df1827Smickey 570f5df1827Smickey#if L3_SLOT_KERNBASE > 0 571f5df1827Smickey movq $NKL3_KIMG_ENTRIES,%rcx 572f5df1827Smickey leaq (PROC0_PTP3_OFF)(%rsi),%rbx 573f5df1827Smickey addq %r8, %rbx 574f5df1827Smickey1: movq $0,(%rbx) 575f5df1827Smickey addq $8,%rbx 576f5df1827Smickey loop 1b 577f5df1827Smickey#endif 578f5df1827Smickey 579f5df1827Smickey movq $NKL4_KIMG_ENTRIES,%rcx 580f5df1827Smickey leaq (PROC0_PML4_OFF)(%rsi),%rbx # old, phys address of PML4 581b5b9857bSart addq %r8, %rbx # new, virtual address of PML4 582f5df1827Smickey1: movq $0,(%rbx) 583f5df1827Smickey addq $8,%rbx 584f5df1827Smickey loop 1b 585f5df1827Smickey 586f5df1827Smickey /* Relocate atdevbase. */ 587f5df1827Smickey movq $(TABLESIZE+KERNBASE),%rdx 588f5df1827Smickey addq %rsi,%rdx 589f5df1827Smickey movq %rdx,_C_LABEL(atdevbase)(%rip) 590f5df1827Smickey 591f5df1827Smickey /* Set up bootstrap stack. */ 592f5df1827Smickey leaq (PROC0_STK_OFF)(%rsi),%rax 593f5df1827Smickey addq %r8,%rax 594f5df1827Smickey movq %rax,_C_LABEL(proc0paddr)(%rip) 595f5df1827Smickey leaq (USPACE-FRAMESIZE)(%rax),%rsp 596f5df1827Smickey movq %rsi,PCB_CR3(%rax) # pcb->pcb_cr3 597f5df1827Smickey xorq %rbp,%rbp # mark end of frames 598f5df1827Smickey 599f5df1827Smickey xorw %ax,%ax 600f5df1827Smickey movw %ax,%gs 601f5df1827Smickey movw %ax,%fs 602f5df1827Smickey 603f5df1827Smickey /* XXX merge these */ 604f5df1827Smickey leaq TABLESIZE(%rsi),%rdi 605f5df1827Smickey call _C_LABEL(init_x86_64) 606f5df1827Smickey 607f5df1827Smickey call _C_LABEL(main) 608f5df1827Smickey 609f5df1827Smickey/*****************************************************************************/ 610f5df1827Smickey 611f5df1827Smickey/* 612f5df1827Smickey * Signal trampoline; copied to top of user stack. 613f5df1827Smickey */ 614f5df1827SmickeyNENTRY(sigcode) 615f5df1827Smickey call *%rax 616f5df1827Smickey 617f5df1827Smickey movq %rsp,%rdi 618f5df1827Smickey pushq %rdi /* fake return address */ 619f5df1827Smickey movq $SYS_sigreturn,%rax 620cb09579aSderaadt int $0x80 621f5df1827Smickey movq $SYS_exit,%rax 622f5df1827Smickey syscall 623f5df1827Smickey .globl _C_LABEL(esigcode) 624f5df1827Smickey_C_LABEL(esigcode): 625f5df1827Smickey 626f5df1827Smickey/* 627f5df1827Smickey * void lgdt(struct region_descriptor *rdp); 628f5df1827Smickey * Change the global descriptor table. 629f5df1827Smickey */ 630f5df1827SmickeyNENTRY(lgdt) 631f5df1827Smickey /* Reload the descriptor table. */ 632f5df1827Smickey movq %rdi,%rax 633f5df1827Smickey lgdt (%rax) 634f5df1827Smickey /* Flush the prefetch q. */ 635f5df1827Smickey jmp 1f 636f5df1827Smickey nop 637f5df1827Smickey1: /* Reload "stale" selectors. */ 638f5df1827Smickey movl $GSEL(GDATA_SEL, SEL_KPL),%eax 639f5df1827Smickey movl %eax,%ds 640f5df1827Smickey movl %eax,%es 641f5df1827Smickey movl %eax,%ss 642f5df1827Smickey /* Reload code selector by doing intersegment return. */ 643f5df1827Smickey popq %rax 644f5df1827Smickey pushq $GSEL(GCODE_SEL, SEL_KPL) 645f5df1827Smickey pushq %rax 646f5df1827Smickey lretq 647f5df1827Smickey 648f5df1827SmickeyENTRY(setjmp) 649f5df1827Smickey /* 650f5df1827Smickey * Only save registers that must be preserved across function 651f5df1827Smickey * calls according to the ABI (%rbx, %rsp, %rbp, %r12-%r15) 652f5df1827Smickey * and %rip. 653f5df1827Smickey */ 654f5df1827Smickey movq %rdi,%rax 655f5df1827Smickey movq %rbx,(%rax) 656f5df1827Smickey movq %rsp,8(%rax) 657f5df1827Smickey movq %rbp,16(%rax) 658f5df1827Smickey movq %r12,24(%rax) 659f5df1827Smickey movq %r13,32(%rax) 660f5df1827Smickey movq %r14,40(%rax) 661f5df1827Smickey movq %r15,48(%rax) 662f5df1827Smickey movq (%rsp),%rdx 663f5df1827Smickey movq %rdx,56(%rax) 664f5df1827Smickey xorl %eax,%eax 665f5df1827Smickey ret 666f5df1827Smickey 667f5df1827SmickeyENTRY(longjmp) 668f5df1827Smickey movq %rdi,%rax 669f5df1827Smickey movq (%rax),%rbx 670f5df1827Smickey movq 8(%rax),%rsp 671f5df1827Smickey movq 16(%rax),%rbp 672f5df1827Smickey movq 24(%rax),%r12 673f5df1827Smickey movq 32(%rax),%r13 674f5df1827Smickey movq 40(%rax),%r14 675f5df1827Smickey movq 48(%rax),%r15 676f5df1827Smickey movq 56(%rax),%rdx 677f5df1827Smickey movq %rdx,(%rsp) 678f5df1827Smickey xorl %eax,%eax 679f5df1827Smickey incl %eax 680f5df1827Smickey ret 681f5df1827Smickey 682f5df1827Smickey/*****************************************************************************/ 683f5df1827Smickey 684f5df1827Smickey/* 685f5df1827Smickey * The following primitives manipulate the run queues. 686f5df1827Smickey * _whichqs tells which of the 32 queues _qs 687f5df1827Smickey * have processes in them. Setrq puts processes into queues, Remrq 688f5df1827Smickey * removes them from queues. The running process is on no queue, 689f5df1827Smickey * other processes are on a queue related to p->p_pri, divided by 4 690f5df1827Smickey * actually to shrink the 0-127 range of priorities into the 32 available 691f5df1827Smickey * queues. 692f5df1827Smickey */ 693f5df1827Smickey .globl _C_LABEL(whichqs),_C_LABEL(qs) 694f5df1827Smickey .globl _C_LABEL(uvmexp),_C_LABEL(panic) 695f5df1827Smickey 696f5df1827Smickey#if NAPM > 0 697f5df1827Smickey .globl _C_LABEL(apm_cpu_idle),_C_LABEL(apm_cpu_busy) 698f5df1827Smickey#endif 699f5df1827Smickey 700f5df1827Smickey#ifdef DIAGNOSTIC 701f5df1827SmickeyNENTRY(switch_error1) 702f5df1827Smickey movabsq $1f,%rdi 703f5df1827Smickey call _C_LABEL(panic) 704f5df1827Smickey /* NOTREACHED */ 705f5df1827Smickey1: .asciz "cpu_switch 1" 706f5df1827SmickeyNENTRY(switch_error2) 707f5df1827Smickey movabsq $1f,%rdi 708f5df1827Smickey call _C_LABEL(panic) 709f5df1827Smickey /* NOTREACHED */ 710f5df1827Smickey1: .asciz "cpu_switch 2" 711f5df1827SmickeyNENTRY(switch_error3) 712f5df1827Smickey movabsq $1f,%rdi 713f5df1827Smickey call _C_LABEL(panic) 714f5df1827Smickey /* NOTREACHED */ 715f5df1827Smickey1: .asciz "cpu_switch 3" 716f5df1827Smickey#endif /* DIAGNOSTIC */ 717f5df1827Smickey 718f5df1827Smickey/* 719b5b9857bSart * int cpu_switch(struct proc *) 720f5df1827Smickey * Find a runnable process and switch to it. Wait if necessary. If the new 721f5df1827Smickey * proc is the same as the old one, we short-circuit the context save and 722f5df1827Smickey * restore. 723f5df1827Smickey */ 724f5df1827SmickeyENTRY(cpu_switch) 725f5df1827Smickey pushq %rbx 726f5df1827Smickey pushq %rbp 727f5df1827Smickey pushq %r12 728f5df1827Smickey pushq %r13 729f5df1827Smickey pushq %r14 730f5df1827Smickey pushq %r15 731f5df1827Smickey 732f5df1827Smickey movq %rdi,%r13 733f5df1827Smickey 734f5df1827Smickey /* 735f5df1827Smickey * Clear curproc so that we don't accumulate system time while idle. 736f5df1827Smickey * This also insures that schedcpu() will move the old proc to 737f5df1827Smickey * the correct queue if it happens to get called from the spllower() 738f5df1827Smickey * below and changes the priority. (See corresponding comment in 739f5df1827Smickey * userret()). 740f5df1827Smickey */ 741f5df1827Smickey movq $0,CPUVAR(CURPROC) 742f5df1827Smickey 743f5df1827Smickey 744f5df1827Smickey /* 745f5df1827Smickey * First phase: find new proc. 746f5df1827Smickey * 747f5df1827Smickey * Registers: 748f5df1827Smickey * %rax - queue head, scratch, then zero 749f5df1827Smickey * %r8 - queue number 750f5df1827Smickey * %ecx - cached value of whichqs 751f5df1827Smickey * %rdx - next process in queue 752f5df1827Smickey * %r13 - old proc 753f5df1827Smickey * %r12 - new proc 754f5df1827Smickey */ 755f5df1827Smickey 756f5df1827Smickey /* Look for new proc. */ 757f5df1827Smickey cli # splhigh doesn't do a cli 758f5df1827Smickey movl _C_LABEL(whichqs)(%rip),%ecx 759b5b9857bSart bsfl %ecx,%r8d # find a full q 760b5b9857bSart jnz switch_dequeue 761f5df1827Smickey 762b5b9857bSart /* 763b5b9857bSart * idling: save old context 764b5b9857bSart * 765b5b9857bSart * Registers: 766b5b9857bSart * %rax, %rcx - scratch 767b5b9857bSart * %r13 - old proc, then old pcb 768b5b9857bSart * %r12 - idle pcb 769b5b9857bSart */ 770b5b9857bSart 771b5b9857bSart /* old proc still in %rdi */ 772b5b9857bSart call _C_LABEL(pmap_deactivate) 773b5b9857bSart 774b5b9857bSart movq P_ADDR(%r13),%r13 775b5b9857bSart 776b5b9857bSart /* Save stack pointers */ 777b5b9857bSart 778b5b9857bSart movq %rsp,PCB_RSP(%r13) 779b5b9857bSart movq %rbp,PCB_RBP(%r13) 780b5b9857bSart 781b5b9857bSart /* Find idle PCB for this CPU */ 782b5b9857bSart#ifndef MULTIPROCESSOR 783b5b9857bSart leaq _C_LABEL(proc0)(%rip),%rcx 784b5b9857bSart movq P_ADDR(%rcx),%r12 785b5b9857bSart movl P_MD_TSS_SEL(%rcx),%edx 786b5b9857bSart#else 787b5b9857bSart movq CPUVAR(IDLE_PCB),%r12 788b5b9857bSart movl CPUVAR(IDLE_TSS_SEL),%edx 789b5b9857bSart#endif 790b5b9857bSart movq $0,CPUVAR(CURPROC) 791b5b9857bSart 792b5b9857bSart /* Restore the idle context (avoid interrupts) */ 793b5b9857bSart cli 794b5b9857bSart 795b5b9857bSart /* Restore stack pointers. */ 796b5b9857bSart movq PCB_RSP(%r12),%rsp 797b5b9857bSart movq PCB_RBP(%r12),%rbp 798b5b9857bSart 799b5b9857bSart /* Switch address space. */ 800b5b9857bSart movq PCB_CR3(%r12),%rcx 801b5b9857bSart movq %rcx,%cr3 802b5b9857bSart 803b5b9857bSart#ifdef MULTIPROCESSOR 804b5b9857bSart movq CPUVAR(GDT),%rax 805b5b9857bSart#else 806b5b9857bSart movq _C_LABEL(gdtstore)(%rip),%rax 807b5b9857bSart#endif 808b5b9857bSart 809b5b9857bSart /* Switch TSS. Reset "task busy" flag before */ 810b5b9857bSart andl $~0x0200,4(%rax,%rdx, 1) 811b5b9857bSart ltr %dx 812b5b9857bSart 813b5b9857bSart /* Restore cr0 (including FPU state). */ 814b5b9857bSart movl PCB_CR0(%r12),%ecx 815b5b9857bSart movq %rcx,%cr0 816b5b9857bSart 817b5b9857bSart SET_CURPCB(%r12) 818b5b9857bSart 819b5b9857bSart xorq %r13,%r13 820b5b9857bSart sti 821b5b9857bSartidle_unlock: 822b5b9857bSart#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 823b5b9857bSart call _C_LABEL(sched_unlock_idle) 824b5b9857bSart#endif 825b5b9857bSart /* Interrupts are okay again. */ 826b5b9857bSart movl $IPL_NONE,%edi 827b5b9857bSart call _C_LABEL(Xspllower) 828b5b9857bSart jmp idle_start 829b5b9857bSartidle_zero: 830b5b9857bSart sti 831b5b9857bSart call _C_LABEL(uvm_pageidlezero) 832b5b9857bSart cli 833b5b9857bSart cmpl $0,_C_LABEL(whichqs)(%rip) 834b5b9857bSart jnz idle_exit 835b5b9857bSartidle_loop: 836b5b9857bSart /* Try to zero some pages. */ 837b5b9857bSart movl _C_LABEL(uvm)+UVM_PAGE_IDLE_ZERO(%rip),%ecx 838b5b9857bSart testl %ecx,%ecx 839b5b9857bSart jnz idle_zero 840b5b9857bSart sti 841b5b9857bSart hlt 842b5b9857bSartNENTRY(mpidle) 843b5b9857bSartidle_start: 844b5b9857bSart cli 845b5b9857bSart cmpl $0,_C_LABEL(whichqs)(%rip) 846b5b9857bSart jz idle_loop 847b5b9857bSartidle_exit: 848b5b9857bSart movl $IPL_HIGH,CPUVAR(ILEVEL) 849b5b9857bSart sti 850b5b9857bSart#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 851b5b9857bSart call _C_LABEL(sched_lock_idle) 852b5b9857bSart#endif 853b5b9857bSartswitch_search: 854b5b9857bSart movl _C_LABEL(whichqs)(%rip),%ecx 855b5b9857bSart bsfl %ecx,%r8d 856b5b9857bSart jz idle_unlock 857f5df1827Smickey 858f5df1827Smickeyswitch_dequeue: 859b5b9857bSart 860b5b9857bSart sti 861f5df1827Smickey movq %r8,%r9 862f5df1827Smickey 863f5df1827Smickey shlq $4, %r9 864f5df1827Smickey leaq _C_LABEL(qs)(%rip),%rax 865f5df1827Smickey addq %r9,%rax 866f5df1827Smickey /* movq (%rax),%rax */ 867f5df1827Smickey 868f5df1827Smickey movq P_FORW(%rax),%r12 # unlink from front of process q 869f5df1827Smickey#ifdef DIAGNOSTIC 870f5df1827Smickey cmpq %r12,%rax # linked to self (i.e. nothing queued)? 871f5df1827Smickey je _C_LABEL(switch_error1) # not possible 872f5df1827Smickey#endif /* DIAGNOSTIC */ 873f5df1827Smickey movq P_FORW(%r12),%rdx 874f5df1827Smickey movq %rdx,P_FORW(%rax) 875f5df1827Smickey movq %rax,P_BACK(%rdx) 876f5df1827Smickey 877f5df1827Smickey cmpq %rdx,%rax # q empty? 878f5df1827Smickey jne 3f 879f5df1827Smickey 880f5df1827Smickey btrl %r8d,%ecx # yes, clear to indicate empty 881f5df1827Smickey movl %ecx,_C_LABEL(whichqs)(%rip) # update q status 882f5df1827Smickey 883f5df1827Smickey3: /* We just did it. */ 884f5df1827Smickey xorq %rax,%rax 885f5df1827Smickey movl %eax,CPUVAR(RESCHED) 886f5df1827Smickeyswitch_resume: 887f5df1827Smickey#ifdef DIAGNOSTIC 888f5df1827Smickey cmpq %rax,P_WCHAN(%r12) 889f5df1827Smickey jne _C_LABEL(switch_error2) 890f5df1827Smickey cmpb $SRUN,P_STAT(%r12) 891f5df1827Smickey jne _C_LABEL(switch_error3) 892f5df1827Smickey#endif 893f5df1827Smickey 894f5df1827Smickey /* Isolate proc. XXX Is this necessary? */ 895f5df1827Smickey movq %rax,P_BACK(%r12) 896f5df1827Smickey 897f5df1827Smickey /* Record new proc. */ 898012ea299Sniklas movb $SONPROC,P_STAT(%r12) # p->p_stat = SONPROC 899f5df1827Smickey SET_CURPROC(%r12,%rcx) 900f5df1827Smickey 901f5df1827Smickey /* Skip context switch if same proc. */ 902b5b9857bSart xorl %ebx,%ebx 903f5df1827Smickey cmpq %r12,%r13 904f5df1827Smickey je switch_return 905f5df1827Smickey 906f5df1827Smickey /* If old proc exited, don't bother. */ 907f5df1827Smickey testq %r13,%r13 908f5df1827Smickey jz switch_exited 909f5df1827Smickey 910f5df1827Smickey /* 911f5df1827Smickey * Second phase: save old context. 912f5df1827Smickey * 913f5df1827Smickey * Registers: 914f5df1827Smickey * %rax, %rcx - scratch 915f5df1827Smickey * %r13 - old proc, then old pcb 916f5df1827Smickey * %r12 - new proc 917f5df1827Smickey */ 918f5df1827Smickey 919b5b9857bSart movq %r13,%rdi 920b5b9857bSart call pmap_deactivate 921b5b9857bSart 922f5df1827Smickey movq P_ADDR(%r13),%r13 923f5df1827Smickey 924f5df1827Smickey /* Save stack pointers. */ 925f5df1827Smickey movq %rsp,PCB_RSP(%r13) 926f5df1827Smickey movq %rbp,PCB_RBP(%r13) 927f5df1827Smickey 928f5df1827Smickeyswitch_exited: 929f5df1827Smickey /* 930f5df1827Smickey * Third phase: restore saved context. 931f5df1827Smickey * 932f5df1827Smickey * Registers: 933f5df1827Smickey * %rax, %rcx, %rdx - scratch 934f5df1827Smickey * %r13 - new pcb 935f5df1827Smickey * %r12 - new process 936f5df1827Smickey */ 937f5df1827Smickey 938f5df1827Smickey /* No interrupts while loading new state. */ 939f5df1827Smickey cli 940f5df1827Smickey movq P_ADDR(%r12),%r13 941f5df1827Smickey 942f5df1827Smickey /* Restore stack pointers. */ 943f5df1827Smickey movq PCB_RSP(%r13),%rsp 944f5df1827Smickey movq PCB_RBP(%r13),%rbp 945f5df1827Smickey 946f5df1827Smickey#if 0 947f5df1827Smickey /* Don't bother with the rest if switching to a system process. */ 948f5df1827Smickey testl $P_SYSTEM,P_FLAG(%r12) 949f5df1827Smickey jnz switch_restored 950f5df1827Smickey#endif 951f5df1827Smickey 952f5df1827Smickey /* Load TSS info. */ 953f5df1827Smickey#ifdef MULTIPROCESSOR 954f5df1827Smickey movq CPUVAR(GDT),%rax 955f5df1827Smickey#else 956f5df1827Smickey movq _C_LABEL(gdtstore)(%rip),%rax 957f5df1827Smickey#endif 958f5df1827Smickey movl P_MD_TSS_SEL(%r12),%edx 959f5df1827Smickey 960f5df1827Smickey /* Switch TSS. Reset "task busy" flag before */ 961f5df1827Smickey andl $~0x0200,4(%rax,%rdx, 1) 962f5df1827Smickey ltr %dx 963f5df1827Smickey 964b5b9857bSart movq %r12,%rdi 965b5b9857bSart call _C_LABEL(pmap_activate) 966b5b9857bSart 967f5df1827Smickey#if 0 968f5df1827Smickeyswitch_restored: 969f5df1827Smickey#endif 970f5df1827Smickey /* Restore cr0 (including FPU state). */ 971f5df1827Smickey movl PCB_CR0(%r13),%ecx 972f5df1827Smickey#ifdef MULTIPROCESSOR 973f5df1827Smickey movq PCB_FPCPU(%r13),%r8 974f5df1827Smickey cmpq CPUVAR(SELF),%r8 975f5df1827Smickey jz 1f 976f5df1827Smickey orl $CR0_TS,%ecx 977f5df1827Smickey1: 978f5df1827Smickey#endif 979f5df1827Smickey movq %rcx,%cr0 980f5df1827Smickey 981f5df1827Smickey SET_CURPCB(%r13) 982f5df1827Smickey 983f5df1827Smickey /* Interrupts are okay again. */ 984f5df1827Smickey sti 985f5df1827Smickey 986f5df1827Smickeyswitch_return: 987f5df1827Smickey#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 988f5df1827Smickey call _C_LABEL(sched_unlock_idle) 989f5df1827Smickey#endif 990b5b9857bSart 991b5b9857bSart movl $IPL_NONE,%edi 992b5b9857bSart call _C_LABEL(Xspllower) 993b5b9857bSart movl $IPL_HIGH,CPUVAR(ILEVEL) 994b5b9857bSart 995b5b9857bSart movl %ebx,%eax 996f5df1827Smickey 997f5df1827Smickey popq %r15 998f5df1827Smickey popq %r14 999f5df1827Smickey popq %r13 1000f5df1827Smickey popq %r12 1001f5df1827Smickey popq %rbp 1002f5df1827Smickey popq %rbx 1003f5df1827Smickey ret 1004f5df1827Smickey 1005f5df1827SmickeyENTRY(cpu_switchto) 1006f5df1827Smickey pushq %rbx 1007f5df1827Smickey pushq %rbp 1008f5df1827Smickey pushq %r12 1009f5df1827Smickey pushq %r13 1010f5df1827Smickey pushq %r14 1011f5df1827Smickey pushq %r15 1012f5df1827Smickey 1013f5df1827Smickey movq %rdi,%r13 1014f5df1827Smickey movq %rsi,%r12 1015f5df1827Smickey 1016f5df1827Smickey movq $0,CPUVAR(CURPROC) 1017f5df1827Smickey 1018f5df1827Smickey xorq %rax,%rax 1019f5df1827Smickey jmp switch_resume 1020f5df1827Smickey 1021f5df1827Smickey 1022f5df1827Smickey/* 1023f5df1827Smickey * void switch_exit(struct proc *l, void (*exit)(struct proc *)); 1024f5df1827Smickey * Switch to proc0's saved context and deallocate the address space and kernel 1025f5df1827Smickey * stack for p. Then jump into cpu_switch(), as if we were in proc0 all along. 1026f5df1827Smickey */ 1027f5df1827Smickey .globl _C_LABEL(proc0),_C_LABEL(uvmspace_free),_C_LABEL(kernel_map) 1028f5df1827Smickey .globl _C_LABEL(uvm_km_free),_C_LABEL(tss_free) 1029f5df1827SmickeyENTRY(switch_exit) 1030f5df1827Smickey#ifdef MULTIPROCESSOR 1031f5df1827Smickey movq CPUVAR(IDLE_PCB),%r8 1032f5df1827Smickey movl CPUVAR(IDLE_TSS_SEL),%edx 1033f5df1827Smickey#else 1034f5df1827Smickey leaq _C_LABEL(proc0)(%rip),%r9 1035f5df1827Smickey movq P_ADDR(%r9),%r8 1036f5df1827Smickey movl P_MD_TSS_SEL(%r9),%edx 1037f5df1827Smickey#endif 1038f5df1827Smickey 1039f5df1827Smickey /* In case we fault... */ 1040f5df1827Smickey movq $0,CPUVAR(CURPROC) 1041f5df1827Smickey 1042f5df1827Smickey cli 1043f5df1827Smickey 1044f5df1827Smickey /* Restore stack pointers. */ 1045f5df1827Smickey movq PCB_RSP(%r8),%rsp 1046f5df1827Smickey movq PCB_RBP(%r8),%rbp 1047f5df1827Smickey 1048f5df1827Smickey /* Load TSS info. */ 1049f5df1827Smickey#ifdef MULTIPROCESSOR 1050f5df1827Smickey movq CPUVAR(GDT),%rax 1051f5df1827Smickey#else 1052f5df1827Smickey movq _C_LABEL(gdtstore)(%rip),%rax 1053f5df1827Smickey#endif 1054f5df1827Smickey 1055f5df1827Smickey /* Switch address space. */ 1056f5df1827Smickey movq PCB_CR3(%r8),%rcx 1057f5df1827Smickey movq %rcx,%cr3 1058f5df1827Smickey 1059f5df1827Smickey /* Switch TSS. */ 1060f5df1827Smickey andl $~0x0200,4-SEL_KPL(%rax,%rdx,1) 1061f5df1827Smickey ltr %dx 1062f5df1827Smickey 1063f5df1827Smickey /* We're always in the kernel, so we don't need the LDT. */ 1064f5df1827Smickey 1065f5df1827Smickey /* Restore cr0 (including FPU state). */ 1066f5df1827Smickey movl PCB_CR0(%r8),%ecx 1067f5df1827Smickey movq %rcx,%cr0 1068f5df1827Smickey 1069f5df1827Smickey /* Record new pcb. */ 1070f5df1827Smickey SET_CURPCB(%r8) 1071f5df1827Smickey 1072f5df1827Smickey /* Interrupts are okay again. */ 1073f5df1827Smickey sti 1074f5df1827Smickey 1075f5df1827Smickey /* 1076f5df1827Smickey * Schedule the dead process's vmspace and stack to be freed. 1077f5df1827Smickey * {lpw_}exit2(l). Function still in %rsi (2nd arg), proc in 1078f5df1827Smickey * %rdi (first arg). 1079f5df1827Smickey */ 1080f5df1827Smickey 1081f5df1827Smickey call *%rsi 1082f5df1827Smickey 1083f5df1827Smickey /* Jump into cpu_switch() with the right state. */ 1084df04b658Sniklas xorq %r13,%r13 1085df04b658Sniklas movq %r13, CPUVAR(CURPROC) 1086f5df1827Smickey jmp switch_search 1087f5df1827Smickey 1088f5df1827Smickey/* 1089f5df1827Smickey * savectx(struct pcb *pcb); 1090f5df1827Smickey * Update pcb, saving current processor state. 1091f5df1827Smickey */ 1092f5df1827SmickeyENTRY(savectx) 1093f5df1827Smickey /* Save stack pointers. */ 1094f5df1827Smickey movq %rsp,PCB_RSP(%rdi) 1095f5df1827Smickey movq %rbp,PCB_RBP(%rdi) 1096f5df1827Smickey 1097f5df1827Smickey ret 1098f5df1827Smickey 1099f5df1827SmickeyIDTVEC(syscall32) 1100f5df1827Smickey sysret /* go away please */ 1101f5df1827Smickey 1102f5df1827Smickey/* 1103f5df1827Smickey * syscall insn entry. This currently isn't much faster, but 1104f5df1827Smickey * it can be made faster in the future. 1105f5df1827Smickey */ 1106f5df1827SmickeyIDTVEC(syscall) 1107f5df1827Smickey swapgs 1108f5df1827Smickey movq %r15,CPUVAR(SCRATCH) 1109f5df1827Smickey movq CPUVAR(CURPCB),%r15 1110f5df1827Smickey movq PCB_RSP0(%r15),%r15 1111f5df1827Smickey xchgq %r15,%rsp 1112f5df1827Smickey sti 1113f5df1827Smickey 1114f5df1827Smickey /* 1115f5df1827Smickey * XXX don't need this whole frame, split of the 1116f5df1827Smickey * syscall frame and trapframe is needed. 1117f5df1827Smickey * First, leave some room for the trapno, error, 1118f5df1827Smickey * ss:rsp, etc, so that all GP registers can be 1119f5df1827Smickey * saved. Then, fill in the rest. 1120f5df1827Smickey */ 1121f5df1827Smickey pushq $(LSEL(LUDATA_SEL, SEL_UPL)) 1122f5df1827Smickey pushq %r15 1123f5df1827Smickey subq $(TF_RSP-TF_TRAPNO),%rsp 1124f5df1827Smickey movq CPUVAR(SCRATCH),%r15 1125f5df1827Smickey subq $32,%rsp 1126f5df1827Smickey INTR_SAVE_GPRS 1127f5df1827Smickey movw %fs,TF_FS(%rsp) 1128f5df1827Smickey movw %gs,TF_GS(%rsp) 1129f5df1827Smickey movw %es,TF_ES(%rsp) 1130f5df1827Smickey movw $(LSEL(LUDATA_SEL, SEL_UPL)),TF_DS(%rsp) 1131f5df1827Smickey movq %r11, TF_RFLAGS(%rsp) /* old rflags from syscall insn */ 1132f5df1827Smickey movq $(LSEL(LUCODE_SEL, SEL_UPL)), TF_CS(%rsp) 1133f5df1827Smickey movq %rcx,TF_RIP(%rsp) 1134f5df1827Smickey movq $2,TF_ERR(%rsp) 1135f5df1827Smickey movq $T_ASTFLT, TF_TRAPNO(%rsp) 1136f5df1827Smickey 1137f5df1827Smickey movq CPUVAR(CURPROC),%r14 1138f5df1827Smickey movq %rsp,P_MD_REGS(%r14) # save pointer to frame 1139f5df1827Smickey andl $~MDP_IRET,P_MD_FLAGS(%r14) 1140b5b9857bSart movq %rsp,%rdi 11414e1a77ceSsturm call _C_LABEL(syscall) 1142f5df1827Smickey1: /* Check for ASTs on exit to user mode. */ 1143f5df1827Smickey cli 1144f5df1827Smickey CHECK_ASTPENDING(%r11) 1145f5df1827Smickey je 2f 1146f5df1827Smickey /* Always returning to user mode here. */ 1147f5df1827Smickey CLEAR_ASTPENDING(%r11) 1148f5df1827Smickey sti 1149f5df1827Smickey /* Pushed T_ASTFLT into tf_trapno on entry. */ 1150b5b9857bSart movq %rsp,%rdi 1151f5df1827Smickey call _C_LABEL(trap) 1152f5df1827Smickey jmp 1b 1153f5df1827Smickey2: 1154f5df1827Smickey sti 1155f5df1827Smickey testl $MDP_IRET, P_MD_FLAGS(%r14) 1156f5df1827Smickey jne iret_return; 1157f5df1827Smickeysyscall_return: 1158f5df1827Smickey#ifdef DIAGNOSTIC 1159b5b9857bSart cmpl $IPL_NONE,CPUVAR(ILEVEL) 1160f5df1827Smickey jne 3f 1161f5df1827Smickey#endif 1162f5df1827Smickey /* 1163f5df1827Smickey * XXX interrupts off longer than they should be here. 1164f5df1827Smickey */ 1165f5df1827Smickey cli 1166f5df1827Smickey swapgs 1167f5df1827Smickey movw TF_ES(%rsp),%es 1168b5b9857bSart movw TF_FS(%rsp),%fs 1169b5b9857bSart movw TF_GS(%rsp),%gs 1170f5df1827Smickey INTR_RESTORE_GPRS 1171b5b9857bSart movw $(LSEL(LUDATA_SEL, SEL_UPL)),%r11 1172b5b9857bSart movw %r11,%ds 1173f5df1827Smickey addq $48,%rsp 1174f5df1827Smickey popq %rcx /* return rip */ 1175f5df1827Smickey addq $8,%rsp 1176f5df1827Smickey popq %r11 /* flags as set by sysret insn */ 1177b5b9857bSart movq %ss:(%rsp),%rsp 1178f5df1827Smickey sysretq 1179f5df1827Smickey 1180f5df1827Smickey#ifdef DIAGNOSTIC 1181f5df1827Smickey3: movabsq $4f, %rdi 1182f5df1827Smickey movl TF_RAX(%rsp),%esi 1183f5df1827Smickey movl TF_RDI(%rsp),%edx 1184f5df1827Smickey movl %ebx,%ecx 1185b5b9857bSart movl CPUVAR(ILEVEL),%r8d 1186f5df1827Smickey xorq %rax,%rax 1187f5df1827Smickey call _C_LABEL(printf) 1188f5df1827Smickey#ifdef DDB 1189f5df1827Smickey int $3 1190f5df1827Smickey#endif /* DDB */ 1191f5df1827Smickey movl $IPL_NONE,CPUVAR(ILEVEL) 1192f5df1827Smickey jmp 1b 1193f5df1827Smickey4: .asciz "WARNING: SPL NOT LOWERED ON SYSCALL %d %d EXIT %x %x\n" 1194f5df1827Smickey#endif 1195f5df1827Smickey 1196f5df1827Smickey 1197f5df1827SmickeyNENTRY(proc_trampoline) 1198f5df1827Smickey#ifdef MULTIPROCESSOR 1199f5df1827Smickey call _C_LABEL(proc_trampoline_mp) 1200f5df1827Smickey#endif 1201f5df1827Smickey movl $IPL_NONE,CPUVAR(ILEVEL) 1202f5df1827Smickey movq %r13,%rdi 1203f5df1827Smickey call *%r12 1204f5df1827Smickey INTRFASTEXIT 1205f5df1827Smickey /* NOTREACHED */ 1206f5df1827Smickey 1207f5df1827SmickeyNENTRY(child_trampoline) 1208f5df1827Smickey#ifdef MULTIPROCESSOR 1209f5df1827Smickey call _C_LABEL(proc_trampoline_mp) 1210f5df1827Smickey#endif 1211f5df1827Smickey movl $IPL_NONE,CPUVAR(ILEVEL) 1212f5df1827Smickey movq %r13,%rdi 1213f5df1827Smickey call *%r12 1214f5df1827Smickey jmp syscall_return 1215f5df1827Smickey 1216f5df1827Smickey .globl _C_LABEL(osyscall_return) 1217f5df1827Smickey 1218b5b9857bSart/* XXX - can we zap the following two? */ 1219b5b9857bSart 1220f5df1827Smickey/* 1221b5b9857bSart * Old call gate entry for syscall. only needed if we're 1222f5df1827Smickey * going to support running old NetBSD or ibcs2 binaries, etc, 1223f5df1827Smickey * on NetBSD/amd64. 1224f5df1827Smickey */ 1225f5df1827SmickeyIDTVEC(oosyscall) 1226f5df1827Smickey /* Set rflags in trap frame. */ 1227f5df1827Smickey pushfq 1228f5df1827Smickey popq 8(%rsp) 1229f5df1827Smickey pushq $7 # size of instruction for restart 1230f5df1827Smickey jmp osyscall1 1231f5df1827Smickey 1232f5df1827Smickey/* 1233f5df1827Smickey * Trap gate entry for int $80 syscall, also used by sigreturn. 1234f5df1827Smickey */ 1235f5df1827SmickeyIDTVEC(osyscall) 1236f5df1827Smickey pushq $2 # size of instruction for restart 1237f5df1827Smickeyosyscall1: 1238f5df1827Smickey pushq $T_ASTFLT # trap # for doing ASTs 1239f5df1827Smickey INTRENTRY 1240f5df1827Smickey sti 1241f5df1827Smickey movq CPUVAR(CURPROC),%rdx 1242f5df1827Smickey movq %rsp,P_MD_REGS(%rdx) # save pointer to frame 1243b5b9857bSart movq %rsp,%rdi 12444e1a77ceSsturm call _C_LABEL(syscall) 1245f5df1827Smickey_C_LABEL(osyscall_return): 1246f5df1827Smickey2: /* Check for ASTs on exit to user mode. */ 1247f5df1827Smickey cli 1248f5df1827Smickey CHECK_ASTPENDING(%r11) 1249f5df1827Smickey je 1f 1250f5df1827Smickey /* Always returning to user mode here. */ 1251f5df1827Smickey CLEAR_ASTPENDING(%r11) 1252f5df1827Smickey sti 1253f5df1827Smickey /* Pushed T_ASTFLT into tf_trapno on entry. */ 1254b5b9857bSart movq %rsp,%rdi 1255f5df1827Smickey call _C_LABEL(trap) 1256f5df1827Smickey jmp 2b 1257b5b9857bSart 1258f5df1827Smickeyiret_return: 1259f5df1827Smickey#ifndef DIAGNOSTIC 1260f5df1827Smickey1: INTRFASTEXIT 1261f5df1827Smickey#else /* DIAGNOSTIC */ 1262f5df1827Smickey1: cmpl $IPL_NONE,CPUVAR(ILEVEL) 1263f5df1827Smickey jne 3f 1264f5df1827Smickey INTRFASTEXIT 1265f5df1827Smickey3: sti 1266f5df1827Smickey movabsq $4f, %rdi 1267f5df1827Smickey xorq %rax,%rax 1268f5df1827Smickey call _C_LABEL(printf) 1269f5df1827Smickey#ifdef DDB 1270f5df1827Smickey int $3 1271f5df1827Smickey#endif /* DDB */ 1272f5df1827Smickey movl $IPL_NONE,CPUVAR(ILEVEL) 1273f5df1827Smickey jmp 2b 1274f5df1827Smickey4: .asciz "WARNING: SPL NOT LOWERED ON SYSCALL EXIT\n" 1275f5df1827Smickey#endif /* DIAGNOSTIC */ 1276