/* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1988 AT&T */ /* All Rights Reserved */ #pragma ident "%Z%%M% %I% %E% SMI" /* from SVr4.0 1.31 */ #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 #include #include #include #include #include #include #include #include #include #include #include #include /* well known processes */ proc_t *proc_sched; /* memory scheduler */ proc_t *proc_init; /* init */ proc_t *proc_pageout; /* pageout daemon */ proc_t *proc_fsflush; /* fsflush daemon */ pgcnt_t maxmem; /* Maximum available memory in pages. */ pgcnt_t freemem; /* Current available memory in pages. */ int audit_active; int interrupts_unleashed; /* set when we do the first spl0() */ kmem_cache_t *process_cache; /* kmem cache for proc structures */ /* * Process 0's lwp directory and lwpid hash table. */ lwpdir_t p0_lwpdir[2]; lwpdir_t *p0_tidhash[2]; lwpent_t p0_lep; /* * Machine-independent initialization code * Called from cold start routine as * soon as a stack and segmentation * have been established. * Functions: * clear and free user core * turn on clock * hand craft 0th process * call all initialization routines * fork - process 0 to schedule * - process 1 execute bootstrap * - process 2 to page out * create system threads */ int cluster_bootflags = 0; void cluster_wrapper(void) { cluster(); panic("cluster() returned"); } char initname[INITNAME_SZ] = "/sbin/init"; char initargs[INITARGS_SZ] = ""; /* * Start the initial user process. * The program [initname] may be invoked with one argument * containing the boot flags. * * It must be a 32-bit program. */ void icode(void) { proc_t *p = ttoproc(curthread); ASSERT_STACK_ALIGNED(); /* * Allocate user address space and stack segment */ proc_init = p; zone0.zone_proc_initpid = proc_init->p_pid; p->p_cstime = p->p_stime = p->p_cutime = p->p_utime = 0; p->p_usrstack = (caddr_t)USRSTACK32; p->p_model = DATAMODEL_ILP32; p->p_stkprot = PROT_ZFOD & ~PROT_EXEC; p->p_datprot = PROT_ZFOD & ~PROT_EXEC; p->p_stk_ctl = INT32_MAX; p->p_as = as_alloc(); p->p_as->a_userlimit = (caddr_t)USERLIMIT32; (void) hat_setup(p->p_as->a_hat, HAT_INIT); init_core(); init_mstate(curthread, LMS_SYSTEM); if (exec_init(initname, 1, initargs[0] == '\0' ? NULL : initargs) != 0) halt("Could not start init"); lwp_rtt(); } int exec_init(const char *initpath, int useboothowto, const char *args) { char *ucp; caddr32_t *uap; char *argv[4]; /* backwards */ int argc = 0; int error = 0, len, count = 0, i; proc_t *p = ttoproc(curthread); klwp_t *lwp = ttolwp(curthread); /* * Construct the exec arguments in userland. That is, make an array * of pointers to the argument strings, just like for execv(). This * is done backwards. */ ucp = p->p_usrstack; argv[0] = NULL; /* argv terminator */ if (args != NULL) { len = strlen(args) + 1; ucp -= len; error |= copyoutstr(args, ucp, len, NULL); argv[++argc] = ucp; } if (useboothowto && boothowto & (RB_SINGLE|RB_RECONFIG|RB_VERBOSE)) { error |= subyte(--ucp, '\0'); /* trailing null byte */ if (boothowto & RB_SINGLE) error |= subyte(--ucp, 's'); if (boothowto & RB_RECONFIG) error |= subyte(--ucp, 'r'); if (boothowto & RB_VERBOSE) error |= subyte(--ucp, 'v'); error |= subyte(--ucp, '-'); /* leading hyphen */ argv[++argc] = ucp; } len = strlen(initpath) + 1; ucp -= len; error |= copyoutstr(initpath, ucp, len, NULL); argv[++argc] = ucp; /* * Move out the arg pointers. */ uap = (caddr32_t *)P2ALIGN((uintptr_t)ucp, sizeof (caddr32_t)); for (i = 0; i < argc + 1; ++i) error |= suword32(--uap, (uint32_t)(uintptr_t)argv[i]); if (error != 0) { zcmn_err(p->p_zone->zone_id, CE_WARN, "Could not construct stack for init.\n"); return (EFAULT); } /* * Point at the arguments. */ lwp->lwp_ap = lwp->lwp_arg; lwp->lwp_arg[0] = (uintptr_t)argv[argc]; lwp->lwp_arg[1] = (uintptr_t)uap; lwp->lwp_arg[2] = NULL; curthread->t_post_sys = 1; curthread->t_sysnum = SYS_execve; again: error = exec_common((const char *)argv[argc], (const char **)uap, NULL); /* * Normally we would just set lwp_argsaved and t_post_sys and * let post_syscall reset lwp_ap for us. Unfortunately, * exec_init isn't always called from a system call. Instead * of making a mess of trap_cleanup, we just reset the args * pointer here. */ reset_syscall_args(); switch (error) { case 0: return (0); case ENOENT: zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed (file not found).\n", initpath); return (ENOENT); case EAGAIN: case EINTR: ++count; if (count < 5) { zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed with errno %d. Retrying...\n", initpath, error); goto again; } } zcmn_err(p->p_zone->zone_id, CE_WARN, "exec(%s) failed with errno %d.", initpath, error); return (error); } void main(void) { proc_t *p = ttoproc(curthread); /* &p0 */ int (**initptr)(); extern void sched(); extern void fsflush(); extern void thread_reaper(); extern int (*init_tbl[])(); extern int (*mp_init_tbl[])(); extern id_t syscid, defaultcid; extern int swaploaded; extern int netboot; extern void vm_init(void); extern void cbe_init(void); extern void clock_init(void); extern void physio_bufs_init(void); extern void pm_cfb_setup_intr(void); extern int pm_adjust_timestamps(dev_info_t *, void *); extern void start_other_cpus(int); extern void sysevent_evc_thrinit(); extern void lgrp_main_init(void); extern void lgrp_main_mp_init(void); /* * In the horrible world of x86 in-lines, you can't get symbolic * structure offsets a la genassym. This assertion is here so * that the next poor slob who innocently changes the offset of * cpu_thread doesn't waste as much time as I just did finding * out that it's hard-coded in i86/ml/i86.il. Similarly for * curcpup. You're welcome. */ ASSERT(CPU == CPU->cpu_self); ASSERT(curthread == CPU->cpu_thread); ASSERT_STACK_ALIGNED(); /* * Setup the first lgroup, and home t0 */ lgrp_setup(); startup(); segkmem_gc(); callb_init(); callout_init(); /* callout table MUST be init'd before clock starts */ cbe_init(); clock_init(); /* * May need to probe to determine latencies from CPU 0 after * gethrtime() comes alive in cbe_init() and before enabling interrupts */ lgrp_plat_probe(); /* * Call all system initialization functions. */ for (initptr = &init_tbl[0]; *initptr; initptr++) (**initptr)(); /* * initialize vm related stuff. */ vm_init(); /* * initialize buffer pool for raw I/O requests */ physio_bufs_init(); ttolwp(curthread)->lwp_error = 0; /* XXX kludge for SCSI driver */ /* * Drop the interrupt level and allow interrupts. At this point * the DDI guarantees that interrupts are enabled. */ (void) spl0(); interrupts_unleashed = 1; vfs_mountroot(); /* Mount the root file system */ errorq_init(); /* after vfs_mountroot() so DDI root is ready */ cpu_kstat_init(CPU); /* after vfs_mountroot() so TOD is valid */ ddi_walk_devs(ddi_root_node(), pm_adjust_timestamps, NULL); /* after vfs_mountroot() so hrestime is valid */ post_startup(); swaploaded = 1; /* * Initial C2 audit system */ #ifdef C2_AUDIT audit_init(); /* C2 hook */ #endif /* * Plumb the protocol modules and drivers only if we are not * networked booted, in this case we already did it in rootconf(). */ if (netboot == 0) (void) strplumb(); gethrestime(&u.u_start); curthread->t_start = u.u_start.tv_sec; p->p_mstart = gethrtime(); /* * Perform setup functions that can only be done after root * and swap have been set up. */ consconfig(); #if defined(__i386) || defined(__amd64) release_bootstrap(); #endif /* * attach drivers with ddi-forceattach prop * This must be done after consconfig() to prevent usb key/mouse * from attaching before the upper console stream is plumbed. * It must be done early enough to load hotplug drivers (e.g. * pcmcia nexus) so that devices enumerated via hotplug is * available before I/O subsystem is fully initialized. */ i_ddi_forceattach_drivers(); /* * Set the scan rate and other parameters of the paging subsystem. */ setupclock(0); /* * Create kmem cache for proc structures */ process_cache = kmem_cache_create("process_cache", sizeof (proc_t), 0, NULL, NULL, NULL, NULL, NULL, 0); /* * Initialize process 0's lwp directory and lwpid hash table. */ p->p_lwpdir = p->p_lwpfree = p0_lwpdir; p->p_lwpdir->ld_next = p->p_lwpdir + 1; p->p_lwpdir_sz = 2; p->p_tidhash = p0_tidhash; p->p_tidhash_sz = 2; p0_lep.le_thread = curthread; p0_lep.le_lwpid = curthread->t_tid; p0_lep.le_start = curthread->t_start; lwp_hash_in(p, &p0_lep); /* * Initialize extended accounting. */ exacct_init(); /* * Initialize threads of sysevent event channels */ sysevent_evc_thrinit(); /* * main lgroup initialization * This must be done after post_startup(), but before * start_other_cpus() */ lgrp_main_init(); /* * Perform MP initialization, if any. */ start_other_cpus(0); /* * Finish lgrp initialization after all CPUS are brought online. */ lgrp_main_mp_init(); /* * After mp_init(), number of cpus are known (this is * true for the time being, when there are actually * hot pluggable cpus then this scheme would not do). * Any per cpu initialization is done here. */ kmem_mp_init(); vmem_update(NULL); for (initptr = &mp_init_tbl[0]; *initptr; initptr++) (**initptr)(); /* * This must be called after start_other_cpus */ pm_cfb_setup_intr(); /* * Make init process; enter scheduling loop with system process. */ /* create init process */ if (newproc(icode, NULL, defaultcid, 59, NULL)) panic("main: unable to fork init."); /* create pageout daemon */ if (newproc(pageout, NULL, syscid, maxclsyspri - 1, NULL)) panic("main: unable to fork pageout()"); /* create fsflush daemon */ if (newproc(fsflush, NULL, syscid, minclsyspri, NULL)) panic("main: unable to fork fsflush()"); /* create cluster process if we're a member of one */ if (cluster_bootflags & CLUSTER_BOOTED) { if (newproc(cluster_wrapper, NULL, syscid, minclsyspri, NULL)) panic("main: unable to fork cluster()"); } /* * Create system threads (threads are associated with p0) */ /* create thread_reaper daemon */ (void) thread_create(NULL, 0, (void (*)())thread_reaper, NULL, 0, &p0, TS_RUN, minclsyspri); /* create module uninstall daemon */ /* BugID 1132273. If swapping over NFS need a bigger stack */ (void) thread_create(NULL, 0, (void (*)())mod_uninstall_daemon, NULL, 0, &p0, TS_RUN, minclsyspri); (void) thread_create(NULL, 0, seg_pasync_thread, NULL, 0, &p0, TS_RUN, minclsyspri); pid_setmin(); bcopy("sched", u.u_psargs, 6); bcopy("sched", u.u_comm, 5); sched(); /* NOTREACHED */ }