/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __xpv #include #endif /* * some globals for patching the result of cpuid * to solve problems w/ creative cpu vendors */ extern uint32_t cpuid_feature_ecx_include; extern uint32_t cpuid_feature_ecx_exclude; extern uint32_t cpuid_feature_edx_include; extern uint32_t cpuid_feature_edx_exclude; /* * Dummy spl priority masks */ static unsigned char dummy_cpu_pri[MAXIPL + 1] = { 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf }; static uint32_t bootprop_getval(char *name) { char prop[32]; u_longlong_t ll; extern struct bootops *bootops; if ((BOP_GETPROPLEN(bootops, name) > sizeof (prop)) || (BOP_GETPROP(bootops, name, prop) < 0) || (kobj_getvalue(prop, &ll) == -1)) return (0); return ((uint32_t)ll); } /* * Setup routine called right before main(). Interposing this function * before main() allows us to call it in a machine-independent fashion. */ void mlsetup(struct regs *rp) { extern struct classfuncs sys_classfuncs; extern disp_t cpu0_disp; extern char t0stack[]; int boot_ncpus; ASSERT_STACK_ALIGNED(); /* * initialize cpu_self */ cpu[0]->cpu_self = cpu[0]; #if defined(__xpv) /* * Point at the hypervisor's virtual cpu structure */ cpu[0]->cpu_m.mcpu_vcpu_info = &HYPERVISOR_shared_info->vcpu_info[0]; #endif /* * Set up dummy cpu_pri_data values till psm spl code is * installed. This allows splx() to work on amd64. */ cpu[0]->cpu_pri_data = dummy_cpu_pri; /* * check if we've got special bits to clear or set * when checking cpu features */ cpuid_feature_ecx_include = bootprop_getval("cpuid_feature_ecx_include"); cpuid_feature_ecx_exclude = bootprop_getval("cpuid_feature_ecx_exclude"); cpuid_feature_edx_include = bootprop_getval("cpuid_feature_edx_include"); cpuid_feature_edx_exclude = bootprop_getval("cpuid_feature_edx_exclude"); /* * The first lightweight pass (pass0) through the cpuid data * was done in locore before mlsetup was called. Do the next * pass in C code. * * The x86_feature bits are set here on the basis of the capabilities * of the boot CPU. Note that if we choose to support CPUs that have * different feature sets (at which point we would almost certainly * want to set the feature bits to correspond to the feature * minimum) this value may be altered. */ x86_feature = cpuid_pass1(cpu[0]); /* * Initialize idt0, gdt0, ldt0_default, ktss0 and dftss. */ init_desctbls(); #if defined(__i386) && !defined(__xpv) /* * Some i386 processors do not implement the rdtsc instruction, * or at least they do not implement it correctly. * * For those that do, patch in the rdtsc instructions in * various parts of the kernel right now while the text is * still writable. */ if (x86_feature & X86_TSC) patch_tsc(); #endif /* __i386 && !__xpv */ #if !defined(__xpv) /* XXPV what, if anything, should be dorked with here under xen? */ /* * While we're thinking about the TSC, let's set up %cr4 so that * userland can issue rdtsc, and initialize the TSC_AUX value * (the cpuid) for the rdtscp instruction on appropriately * capable hardware. */ if (x86_feature & X86_TSC) setcr4(getcr4() & ~CR4_TSD); if (x86_feature & X86_TSCP) (void) wrmsr(MSR_AMD_TSCAUX, 0); if (x86_feature & X86_DE) setcr4(getcr4() | CR4_DE); #endif /* __xpv */ /* * initialize t0 */ t0.t_stk = (caddr_t)rp - MINFRAME; t0.t_stkbase = t0stack; t0.t_pri = maxclsyspri - 3; t0.t_schedflag = TS_LOAD | TS_DONT_SWAP; t0.t_procp = &p0; t0.t_plockp = &p0lock.pl_lock; t0.t_lwp = &lwp0; t0.t_forw = &t0; t0.t_back = &t0; t0.t_next = &t0; t0.t_prev = &t0; t0.t_cpu = cpu[0]; t0.t_disp_queue = &cpu0_disp; t0.t_bind_cpu = PBIND_NONE; t0.t_bind_pset = PS_NONE; t0.t_cpupart = &cp_default; t0.t_clfuncs = &sys_classfuncs.thread; t0.t_copyops = NULL; THREAD_ONPROC(&t0, CPU); lwp0.lwp_thread = &t0; lwp0.lwp_regs = (void *)rp; lwp0.lwp_procp = &p0; t0.t_tid = p0.p_lwpcnt = p0.p_lwprcnt = p0.p_lwpid = 1; p0.p_exec = NULL; p0.p_stat = SRUN; p0.p_flag = SSYS; p0.p_tlist = &t0; p0.p_stksize = 2*PAGESIZE; p0.p_stkpageszc = 0; p0.p_as = &kas; p0.p_lockp = &p0lock; p0.p_brkpageszc = 0; p0.p_t1_lgrpid = LGRP_NONE; p0.p_tr_lgrpid = LGRP_NONE; sigorset(&p0.p_ignore, &ignoredefault); CPU->cpu_thread = &t0; bzero(&cpu0_disp, sizeof (disp_t)); CPU->cpu_disp = &cpu0_disp; CPU->cpu_disp->disp_cpu = CPU; CPU->cpu_dispthread = &t0; CPU->cpu_idle_thread = &t0; CPU->cpu_flags = CPU_READY | CPU_RUNNING | CPU_EXISTS | CPU_ENABLE; CPU->cpu_dispatch_pri = t0.t_pri; CPU->cpu_id = 0; CPU->cpu_pri = 12; /* initial PIL for the boot CPU */ /* * The kernel doesn't use LDTs unless a process explicitly requests one. */ p0.p_ldt_desc = null_sdesc; /* * Initialize thread/cpu microstate accounting */ init_mstate(&t0, LMS_SYSTEM); init_cpu_mstate(CPU, CMS_SYSTEM); /* * Initialize lists of available and active CPUs. */ cpu_list_init(CPU); /* * Now that we have taken over the GDT, IDT and have initialized * active CPU list it's time to inform kmdb if present. */ if (boothowto & RB_DEBUG) kdi_idt_sync(); /* * If requested (boot -d) drop into kmdb. * * This must be done after cpu_list_init() on the 64-bit kernel * since taking a trap requires that we re-compute gsbase based * on the cpu list. */ if (boothowto & RB_DEBUGENTER) kmdb_enter(); cpu_vm_data_init(CPU); /* lgrp_init() needs PCI config space access */ #if defined(__xpv) if (DOMAIN_IS_INITDOMAIN(xen_info)) pci_cfgspace_init(); #else pci_cfgspace_init(); #endif /* * Initialize the lgrp framework */ lgrp_init(); rp->r_fp = 0; /* terminate kernel stack traces! */ prom_init("kernel", (void *)NULL); boot_ncpus = bootprop_getval("boot-ncpus"); if (boot_ncpus <= 0 || boot_ncpus > NCPU) boot_ncpus = NCPU; max_ncpus = boot_max_ncpus = boot_ncpus; if (boothowto & RB_HALT) { prom_printf("unix: kernel halted by -h flag\n"); prom_enter_mon(); } ASSERT_STACK_ALIGNED(); #if !defined(__xpv) /* * Fill out cpu_ucode_info. Update microcode if necessary. */ ucode_check(CPU); #endif if (workaround_errata(CPU) != 0) panic("critical workaround(s) missing for boot cpu"); }