Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
1acdbcea KB |
2 | * Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
adb35f79 KB |
4 | * (c) UNIX System Laboratories, Inc. |
5 | * All or some portions of this file are derived from material licensed | |
6 | * to the University of California by American Telephone and Telegraph | |
7 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
8 | * the permission of UNIX System Laboratories, Inc. | |
da7c5cc6 | 9 | * |
2d9d8fa8 MK |
10 | * %sccs.include.redist.c% |
11 | * | |
3ef0a118 | 12 | * @(#)init_main.c 8.10 (Berkeley) %G% |
da7c5cc6 | 13 | */ |
961945a8 | 14 | |
d89c95b4 KM |
15 | #include <sys/param.h> |
16 | #include <sys/filedesc.h> | |
1ccd5ccc KM |
17 | #include <sys/errno.h> |
18 | #include <sys/exec.h> | |
d89c95b4 KM |
19 | #include <sys/kernel.h> |
20 | #include <sys/mount.h> | |
21 | #include <sys/map.h> | |
22 | #include <sys/proc.h> | |
23 | #include <sys/resourcevar.h> | |
24 | #include <sys/signalvar.h> | |
25 | #include <sys/systm.h> | |
26 | #include <sys/vnode.h> | |
27 | #include <sys/conf.h> | |
28 | #include <sys/buf.h> | |
29 | #include <sys/clist.h> | |
0d6eb1b7 | 30 | #include <sys/device.h> |
d89c95b4 KM |
31 | #include <sys/protosw.h> |
32 | #include <sys/reboot.h> | |
33 | #include <sys/user.h> | |
c040c6b1 | 34 | |
d301d150 | 35 | |
d89c95b4 | 36 | #include <machine/cpu.h> |
961945a8 | 37 | |
d89c95b4 | 38 | #include <vm/vm.h> |
d7db4999 | 39 | |
875b0815 KM |
40 | #ifdef HPFPLIB |
41 | char copyright[] = | |
d8c34843 | 42 | "Copyright (c) 1982, 1986, 1989, 1991, 1993\n\tThe Regents of the University of California.\nCopyright (c) 1992 Hewlett-Packard Company\nCopyright (c) 1992 Motorola Inc.\nAll rights reserved.\n\n"; |
875b0815 | 43 | #else |
94d045fa | 44 | char copyright[] = |
d8c34843 | 45 | "Copyright (c) 1982, 1986, 1989, 1991, 1993\n\tThe Regents of the University of California. All rights reserved.\n\n"; |
875b0815 | 46 | #endif |
94d045fa | 47 | |
802236f4 | 48 | /* Components of the first process -- never freed. */ |
d7db4999 MK |
49 | struct session session0; |
50 | struct pgrp pgrp0; | |
51 | struct proc proc0; | |
52 | struct pcred cred0; | |
c040c6b1 | 53 | struct filedesc0 filedesc0; |
d7db4999 MK |
54 | struct plimit limit0; |
55 | struct vmspace vmspace0; | |
c040c6b1 | 56 | struct proc *curproc = &proc0; |
d7db4999 | 57 | struct proc *initproc, *pageproc; |
9d4095a1 | 58 | |
28c7a4c5 | 59 | int cmask = CMASK; |
f657c741 | 60 | extern struct user *proc0paddr; |
362786f8 | 61 | |
94d045fa MK |
62 | struct vnode *rootvp, *swapdev_vp; |
63 | int boothowto; | |
31390dba | 64 | struct timeval boottime; |
571f7085 | 65 | struct timeval runtime; |
94d045fa | 66 | |
bd65f614 | 67 | static void start_init __P((struct proc *p, void *framep)); |
1ccd5ccc | 68 | |
c4708522 | 69 | /* |
802236f4 KB |
70 | * System startup; initialize the world, create process 0, mount root |
71 | * filesystem, and fork to create init and pagedaemon. Most of the | |
72 | * hard work is done in the lower-level initialization routines including | |
73 | * startup(), which does memory initialization and autoconfiguration. | |
c4708522 | 74 | */ |
bd65f614 KM |
75 | main(framep) |
76 | void *framep; | |
c4708522 | 77 | { |
dd4b582c | 78 | register struct proc *p; |
c040c6b1 | 79 | register struct filedesc0 *fdp; |
0d6eb1b7 | 80 | register struct pdevinit *pdev; |
802236f4 | 81 | register int i; |
d7db4999 | 82 | int s, rval[2]; |
802236f4 | 83 | extern int (*mountroot) __P((void)); |
0d6eb1b7 | 84 | extern struct pdevinit pdevinit[]; |
571f7085 CT |
85 | extern void roundrobin __P((void *)); |
86 | extern void schedcpu __P((void *)); | |
083baeb6 | 87 | |
362786f8 | 88 | /* |
802236f4 KB |
89 | * Initialize the current process pointer (curproc) before |
90 | * any possible traps/probes to simplify trap processing. | |
362786f8 | 91 | */ |
d7db4999 MK |
92 | p = &proc0; |
93 | curproc = p; | |
9d4095a1 | 94 | /* |
d7db4999 MK |
95 | * Attempt to find console and initialize |
96 | * in case of early panic or other messages. | |
9d4095a1 | 97 | */ |
d7db4999 | 98 | consinit(); |
94d045fa | 99 | printf(copyright); |
d7db4999 | 100 | |
9d4095a1 KM |
101 | vm_mem_init(); |
102 | kmeminit(); | |
27bff27d | 103 | cpu_startup(); |
c4708522 | 104 | |
3ef0a118 KM |
105 | /* |
106 | * Initialize process and pgrp structures. | |
107 | */ | |
108 | procinit(); | |
109 | ||
61b0bd0a KM |
110 | /* |
111 | * Create process 0 (the swapper). | |
112 | */ | |
3ef0a118 | 113 | LIST_INSERT_HEAD(&allproc, p, p_list); |
d7db4999 | 114 | p->p_pgrp = &pgrp0; |
3ef0a118 KM |
115 | LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); |
116 | LIST_INIT(&pgrp0.pg_members); | |
117 | LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); | |
118 | ||
d7db4999 MK |
119 | pgrp0.pg_session = &session0; |
120 | session0.s_count = 1; | |
121 | session0.s_leader = p; | |
122 | ||
cf5ef508 | 123 | p->p_flag = P_INMEM | P_SYSTEM; |
dd4b582c | 124 | p->p_stat = SRUN; |
dd4b582c | 125 | p->p_nice = NZERO; |
d7db4999 MK |
126 | bcopy("swapper", p->p_comm, sizeof ("swapper")); |
127 | ||
802236f4 | 128 | /* Create credentials. */ |
2dd3075b | 129 | cred0.p_refcnt = 1; |
d7db4999 MK |
130 | p->p_cred = &cred0; |
131 | p->p_ucred = crget(); | |
132 | p->p_ucred->cr_ngroups = 1; /* group 0 */ | |
fb1db32c | 133 | |
802236f4 | 134 | /* Create the file descriptor table. */ |
d7db4999 | 135 | fdp = &filedesc0; |
c040c6b1 MK |
136 | p->p_fd = &fdp->fd_fd; |
137 | fdp->fd_fd.fd_refcnt = 1; | |
138 | fdp->fd_fd.fd_cmask = cmask; | |
139 | fdp->fd_fd.fd_ofiles = fdp->fd_dfiles; | |
140 | fdp->fd_fd.fd_ofileflags = fdp->fd_dfileflags; | |
141 | fdp->fd_fd.fd_nfiles = NDFILE; | |
d7db4999 | 142 | |
802236f4 | 143 | /* Create the limits structures. */ |
d7db4999 MK |
144 | p->p_limit = &limit0; |
145 | for (i = 0; i < sizeof(p->p_rlimit)/sizeof(p->p_rlimit[0]); i++) | |
146 | limit0.pl_rlimit[i].rlim_cur = | |
147 | limit0.pl_rlimit[i].rlim_max = RLIM_INFINITY; | |
50b95cfe | 148 | limit0.pl_rlimit[RLIMIT_NOFILE].rlim_cur = NOFILE; |
d7db4999 | 149 | limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = MAXUPRC; |
6db5115e KM |
150 | i = ptoa(cnt.v_free_count); |
151 | limit0.pl_rlimit[RLIMIT_RSS].rlim_max = i; | |
152 | limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_max = i; | |
153 | limit0.pl_rlimit[RLIMIT_MEMLOCK].rlim_cur = i / 3; | |
d7db4999 MK |
154 | limit0.p_refcnt = 1; |
155 | ||
802236f4 | 156 | /* Allocate a prototype map so we have something to fork. */ |
d7db4999 MK |
157 | p->p_vmspace = &vmspace0; |
158 | vmspace0.vm_refcnt = 1; | |
159 | pmap_pinit(&vmspace0.vm_pmap); | |
160 | vm_map_init(&p->p_vmspace->vm_map, round_page(VM_MIN_ADDRESS), | |
161 | trunc_page(VM_MAX_ADDRESS), TRUE); | |
162 | vmspace0.vm_map.pmap = &vmspace0.vm_pmap; | |
163 | p->p_addr = proc0paddr; /* XXX */ | |
164 | ||
165 | /* | |
802236f4 KB |
166 | * We continue to place resource usage info and signal |
167 | * actions in the user struct so they're pageable. | |
d7db4999 | 168 | */ |
f657c741 MK |
169 | p->p_stats = &p->p_addr->u_stats; |
170 | p->p_sigacts = &p->p_addr->u_sigacts; | |
d7db4999 | 171 | |
06a043ee | 172 | /* |
3ef0a118 | 173 | * Charge root for one process. |
06a043ee | 174 | */ |
06a043ee KM |
175 | (void)chgproccnt(0, 1); |
176 | ||
d7db4999 MK |
177 | rqinit(); |
178 | ||
0d6eb1b7 | 179 | /* Configure virtual memory system, set vm rlimits. */ |
d7db4999 | 180 | vm_init_limits(p); |
8ede3c1b | 181 | |
0d6eb1b7 | 182 | /* Initialize the file systems. */ |
85570e35 | 183 | vfsinit(); |
475798b6 | 184 | |
0d6eb1b7 | 185 | /* Start real time and statistics clocks. */ |
571f7085 | 186 | initclocks(); |
c4708522 | 187 | |
802236f4 | 188 | /* Initialize mbuf's. */ |
d872f034 | 189 | mbinit(); |
802236f4 KB |
190 | |
191 | /* Initialize clists. */ | |
192 | clist_init(); | |
193 | ||
933220e9 | 194 | #ifdef SYSVSHM |
802236f4 | 195 | /* Initialize System V style shared memory. */ |
933220e9 KM |
196 | shminit(); |
197 | #endif | |
0d6eb1b7 CT |
198 | |
199 | /* Attach pseudo-devices. */ | |
200 | for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++) | |
201 | (*pdev->pdev_attach)(pdev->pdev_count); | |
202 | ||
4f083fd7 | 203 | /* |
0d6eb1b7 CT |
204 | * Initialize protocols. Block reception of incoming packets |
205 | * until everything is ready. | |
4f083fd7 SL |
206 | */ |
207 | s = splimp(); | |
fbf9a431 | 208 | ifinit(); |
b7892118 | 209 | domaininit(); |
4f083fd7 | 210 | splx(s); |
d7db4999 | 211 | |
e6254ffb | 212 | #ifdef GPROF |
802236f4 | 213 | /* Initialize kernel profiling. */ |
e6254ffb BJ |
214 | kmstartup(); |
215 | #endif | |
9d6d37ce | 216 | |
802236f4 | 217 | /* Kick off timeout driven events by calling first time. */ |
571f7085 CT |
218 | roundrobin(NULL); |
219 | schedcpu(NULL); | |
27b91f59 | 220 | |
802236f4 | 221 | /* Mount the root file system. */ |
475798b6 KM |
222 | if ((*mountroot)()) |
223 | panic("cannot mount root"); | |
802236f4 KB |
224 | |
225 | /* Get the vnode for '/'. Set fdp->fd_fd.fd_cdir to reference it. */ | |
af50abe6 | 226 | if (VFS_ROOT(mountlist.tqh_first, &rootvnode)) |
475798b6 | 227 | panic("cannot find root vnode"); |
802236f4 | 228 | fdp->fd_fd.fd_cdir = rootvnode; |
c040c6b1 | 229 | VREF(fdp->fd_fd.fd_cdir); |
802236f4 | 230 | VOP_UNLOCK(rootvnode); |
c040c6b1 | 231 | fdp->fd_fd.fd_rdir = NULL; |
d7db4999 | 232 | swapinit(); |
c4708522 | 233 | |
28c7a4c5 | 234 | /* |
38fab586 KM |
235 | * Now can look at time, having had a chance to verify the time |
236 | * from the file system. Reset p->p_rtime as it may have been | |
cf5ef508 | 237 | * munched in mi_switch() after the time got set. |
28c7a4c5 | 238 | */ |
d4f004e2 | 239 | p->p_stats->p_start = runtime = mono_time = boottime = time; |
38fab586 | 240 | p->p_rtime.tv_sec = p->p_rtime.tv_usec = 0; |
28c7a4c5 | 241 | |
802236f4 | 242 | /* Initialize signal state for process 0. */ |
d7db4999 | 243 | siginit(p); |
802236f4 KB |
244 | |
245 | /* Create process 1 (init(8)). */ | |
fb06b384 | 246 | if (fork(p, NULL, rval)) |
d7db4999 MK |
247 | panic("fork init"); |
248 | if (rval[1]) { | |
bd65f614 | 249 | start_init(curproc, framep); |
1ccd5ccc | 250 | return; |
28c7a4c5 | 251 | } |
d7db4999 | 252 | |
802236f4 | 253 | /* Create process 2 (the pageout daemon). */ |
fb06b384 | 254 | if (fork(p, NULL, rval)) |
d7db4999 MK |
255 | panic("fork pager"); |
256 | if (rval[1]) { | |
257 | /* | |
258 | * Now in process 2. | |
259 | */ | |
260 | p = curproc; | |
261 | pageproc = p; | |
cf5ef508 | 262 | p->p_flag |= P_INMEM | P_SYSTEM; /* XXX */ |
d7db4999 | 263 | bcopy("pagedaemon", curproc->p_comm, sizeof ("pagedaemon")); |
9d4095a1 | 264 | vm_pageout(); |
802236f4 | 265 | /* NOTREACHED */ |
c4708522 BJ |
266 | } |
267 | ||
802236f4 KB |
268 | /* The scheduler is an infinite loop. */ |
269 | scheduler(); | |
270 | /* NOTREACHED */ | |
c4708522 | 271 | } |
1ccd5ccc KM |
272 | |
273 | /* | |
274 | * List of paths to try when searching for "init". | |
275 | */ | |
276 | static char *initpaths[] = { | |
277 | "/sbin/init", | |
278 | "/sbin/oinit", | |
279 | "/sbin/init.bak", | |
280 | NULL, | |
281 | }; | |
282 | ||
283 | /* | |
284 | * Start the initial user process; try exec'ing each pathname in "initpaths". | |
285 | * The program is invoked with one argument containing the boot flags. | |
286 | */ | |
287 | static void | |
bd65f614 | 288 | start_init(p, framep) |
1ccd5ccc | 289 | struct proc *p; |
bd65f614 | 290 | void *framep; |
1ccd5ccc KM |
291 | { |
292 | vm_offset_t addr; | |
293 | struct execve_args args; | |
294 | int options, i, retval[2], error; | |
295 | char **pathp, *path, *ucp, **uap, *arg0, *arg1; | |
b4607756 MH |
296 | |
297 | initproc = p; | |
1ccd5ccc KM |
298 | |
299 | /* | |
bd65f614 KM |
300 | * We need to set the system call frame as if we were entered through |
301 | * a syscall() so that when we call execve() below, it will be able | |
302 | * to set the entry point (see setregs) when it tries to exec. The | |
303 | * startup code in "locore.s" has allocated space for the frame and | |
304 | * passed a pointer to that space as main's argument. | |
1ccd5ccc | 305 | */ |
bd65f614 | 306 | cpu_set_init_frame(p, framep); |
1ccd5ccc KM |
307 | |
308 | /* | |
309 | * Need just enough stack to hold the faked-up "execve()" arguments. | |
310 | */ | |
311 | addr = trunc_page(VM_MAX_ADDRESS - PAGE_SIZE); | |
312 | if (vm_allocate(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, FALSE) != 0) | |
313 | panic("init: couldn't allocate argument space"); | |
314 | p->p_vmspace->vm_maxsaddr = (caddr_t)addr; | |
315 | ||
316 | for (pathp = &initpaths[0]; (path = *pathp) != NULL; pathp++) { | |
317 | /* | |
318 | * Move out the boot flag argument. | |
319 | */ | |
320 | options = 0; | |
321 | ucp = (char *)USRSTACK; | |
cf5ef508 | 322 | (void)subyte(--ucp, 0); /* trailing zero */ |
1ccd5ccc | 323 | if (boothowto & RB_SINGLE) { |
cf5ef508 | 324 | (void)subyte(--ucp, 's'); |
1ccd5ccc KM |
325 | options = 1; |
326 | } | |
327 | #ifdef notyet | |
328 | if (boothowto & RB_FASTBOOT) { | |
cf5ef508 | 329 | (void)subyte(--ucp, 'f'); |
1ccd5ccc KM |
330 | options = 1; |
331 | } | |
332 | #endif | |
333 | if (options == 0) | |
cf5ef508 KB |
334 | (void)subyte(--ucp, '-'); |
335 | (void)subyte(--ucp, '-'); /* leading hyphen */ | |
1ccd5ccc KM |
336 | arg1 = ucp; |
337 | ||
338 | /* | |
339 | * Move out the file name (also arg 0). | |
340 | */ | |
341 | for (i = strlen(path) + 1; i >= 0; i--) | |
cf5ef508 | 342 | (void)subyte(--ucp, path[i]); |
1ccd5ccc KM |
343 | arg0 = ucp; |
344 | ||
345 | /* | |
346 | * Move out the arg pointers. | |
347 | */ | |
348 | uap = (char **)((int)ucp & ~(NBPW-1)); | |
cf5ef508 KB |
349 | (void)suword((caddr_t)--uap, 0); /* terminator */ |
350 | (void)suword((caddr_t)--uap, (int)arg1); | |
351 | (void)suword((caddr_t)--uap, (int)arg0); | |
1ccd5ccc KM |
352 | |
353 | /* | |
354 | * Point at the arguments. | |
355 | */ | |
356 | args.fname = arg0; | |
357 | args.argp = uap; | |
358 | args.envp = NULL; | |
359 | ||
360 | /* | |
cf5ef508 KB |
361 | * Now try to exec the program. If can't for any reason |
362 | * other than it doesn't exist, complain. | |
1ccd5ccc KM |
363 | */ |
364 | if ((error = execve(p, &args, &retval)) == 0) | |
365 | return; | |
cf5ef508 KB |
366 | if (error != ENOENT) |
367 | printf("exec %s: error %d\n", path, error); | |
1ccd5ccc KM |
368 | } |
369 | printf("init: not found\n"); | |
370 | panic("no init"); | |
371 | } |