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