1 static char *rcsid = "$Id: minix.c,v 1.4 1996/07/09 04:47:04 paul Exp $";
2
3 /*
4 * This program is responsible for booting Solaris Minix. The
5 * code in config.c is resposible for reading the configuration file
6 * and setting up all smx devices. The code in minix_load.c is
7 * responsible for loading Minix executable programs into smx
8 * "physical" memory. The code in this file coordinates the whole process.
9 *
10 * Two processes are involved in running smx. The parent process (the one
11 * that starts by running main) forks off the child, and it is the
12 * child that actually becomes smx. When the child exits, the parent
13 * is there to cleanup.
14 *
15 * The bootstrapping process involves reading the configuration file,
16 * establishing all smx devices, allocating the "physical" memory for smx,
17 * loading four programs from the Minix image file (kernel, mm, fs, init)
18 * into this memory, then switching execution into smx.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <malloc.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/wait.h>
28 #include <sys/param.h>
29 #include <sys/types.h>
30
31 #include "../../include/minix/config.h"
32 #undef HZ /* Defined again in minix/const.h */
33 #undef NULL /* Defined again in minix/const.h */
34 #include "../../include/minix/const.h"
35 #include "../kernel/const.h" /* Need RAM_FD */
36 typedef unsigned char u8_t;
37 typedef unsigned short u16_t, U16_t;
38 #include "../../include/net/gen/ether.h"
39 #include "../kernel/bootinfo.h"
40
41 #undef PRIVATE /* Defined in <sys/mman.h? */
42 #undef printf
43
44 #include <sys/mman.h>
45
46
47 #include "config.h"
48 #include "minix_load.h"
49
50 #define DEF_MEM_SIZE 3072 /* default number of kbytes of smx memory */
51 #define DEF_PROTECT 1 /* default protection level */
52
53 #define USAGE "%s [-d] [-m (none|half|full)] [config-file]\n"
54
55
56 char *progname;
57 static int debug = 0; /* Used in this program, and propagated to smx */
58
59 /*
60 * Local functions.
61 */
62 static struct smx_bootinfo *load_image(const char *imagefile, long core_size);
63 static void allocate_memory(unsigned long memory_base, long ram_size);
64
65 static void smx_parent(void);
66
67 static void usage(void);
68
69
70 /*
71 * Function: main
72 * Parameters: argc, argv - command line argument summary appears in the USAGE
73 * string
74 *
75 * The main function begins by processing the command line arguments.
76 * It then calls config to have the configuration file read and
77 * the smx devices opened. It then calls fork, with the parent
78 * waiting to clean up after smx and the child loading the four initial
79 * programs and jumping inside smx.
80 */
81 int main(int argc, char *argv[])
82 {
83 char image_name[MAXPATHLEN];
84 int protect, configdebug, configprotect;
85 long core_size; /* how much memory is allocated */
86 char *config_file;
87 struct smx_bootinfo *bootp; /* this will actually be part of the */
88 /* kernel's data segment */
89 ether_addr_t eaddr = { {0} }; /* all 0s means disabled */
90
91 progname = argv[0];
92
93 /*
94 * Check that the click size is a multiple of the pagesize - otherwise
95 * protection of segments using mprotect(2) will fail.
96 */
97 if (CLICK_SIZE % sysconf(_SC_PAGESIZE) != 0) {
98 (void) fprintf(stderr,
99 "%s: Minix aborted - clicksize (%d) is not a multiple of pagesize (%ld)\n",
100 progname, CLICK_SIZE, sysconf(_SC_PAGESIZE));
101 exit(1);
102 }
103
104 /*
105 * Process options. Only the debug (-d) and the three memory
106 * protection levels (-m none, -m half, -m full) are accepted
107 */
108 config_file = 0; /* Initialise things that may be found .. */
109 debug = 0; /* on the command line */
110 protect = -1;
111 {
112 int option;
113 extern char *optarg;
114 extern int optind;
115
116 while ((option = getopt(argc, argv, "dm:")) != -1) {
117 switch(option) {
118 case 'd':
119 debug = 1;
120 break;
121
122 case 'm':
123 protect = prot_atoi(optarg);
124 break;
125
126 default:
127 /*
128 * unknown argument.
129 */
130 usage();
131 break;
132 }
133 }
134 argc -= optind; /* set to the number of args remaining */
135 argv += optind; /* step over already processed args */
136 }
137
138 if (argc > 1) {
139 usage();
140 }
141 if (argc == 1) {
142 config_file = *argv;
143 }
144
145
146 /*
147 * Open all disk files etc. and get the desired memory size, image file
148 * name, protection level and debug mode. Three things that might be
149 * specified in the config file are memory size, debug enable and
150 * protection. Variables are set to defaults before the call
151 * to config, and if the relevant option is not specified in the config
152 * file, the value ofthe variable is not changed.
153 */
154 core_size = DEF_MEM_SIZE * 1024;
155 configprotect = DEF_PROTECT;
156 configdebug = 0;
157 config(config_file, &core_size, image_name, &configprotect, &configdebug,
158 &eaddr);
159 /*
160 * Round up core size to the next click
161 */
162 core_size = upclick(core_size);
163
164 /*
165 * Config file protection and debug options are only used if the relevant
166 * command line option was not given.
167 * file options.
168 */
169 if (!debug) {
170 debug = configdebug;
171 }
172 if (protect == -1) {
173 protect = configprotect;
174 }
175
176 /*
177 * Create the process to run smx.
178 */
179 switch (fork()) {
180 case -1: /* error */
181 reset_devices();
182 fprintf(stderr, "%s: Unable to fork secondary Minix process\n",
183 progname);
184 exit(1);
185
186 case 0: /* child */
187 break;
188
189 default: /* parent */
190 smx_parent();
191 /*NOTREACHED*/
192 } /* fork() switch */
193
194 bootp = load_image(image_name, core_size);
195 bootp->debug = debug;
196 bootp->prot_lev = protect;
197 bootp->mem_bytes = core_size;
198 bootp->ether_addr = eaddr;
199
200 enable_interrupts();
201
202 /* start the kernel running */
203 ((void (*)()) bootp->prog[KERNEL_PROG].entry)();
204 /*NOTREACHED*/
205 exit(2);
206 }
207
208
209 /*
210 * Function: load_image
211 * Parameters: imagefile - file to load the 4 programs from
212 * core_size - number of bytes of smx "physical" memory to allocate
213 * Returns: pointer to the smx_bootinfo struct which is at the start of the
214 * kernel's data segment.
215 *
216 * Details of the kernel's text segment are retrieved so that we know where
217 * to position the smx memory, and where the kernel data segment starts
218 * so that we can determine where the smx_bootinfo struct is. The memory
219 * is then allocated, and the four programs from the image loaded into it,
220 * with program details stored in the bootinfo struct.
221 */
222 static struct smx_bootinfo *load_image(const char *imagefile, long core_size)
223 {
224 int fd, prog;
225 struct smx_bootinfo *bootp;
226 unsigned long memory_base;
227 char *base;
228
229 /*
230 * Open the image file.
231 */
232 if ((fd = open(imagefile, O_RDONLY)) < 0){
233 fprintf(stderr, "%s: Unable to open image file\n", progname);
234 exit(1);
235 }
236
237 /*
238 * Find out where the kernel text segment starts (that's where we need
239 * to map smx memory) and where the kernel data segment starts
240 * (that's where the boot parameters go)
241 */
242 if (get_seg_details(fd, &memory_base, (unsigned long *)&bootp) < 0) {
243 fprintf(stderr, "%s: Failed to get address of kernel text segment\n",
244 progname);
245 exit(1);
246 }
247 if (debug) {
248 fprintf(stderr, "bootp = 0x%x\n", (unsigned) bootp);
249 }
250
251 allocate_memory(memory_base, core_size);
252 if (debug) {
253 (void) fprintf(stderr, "Core size = 0x%x\nMemory base = 0x%lx\n",
254 (unsigned) core_size, memory_base);
255 }
256
257 /*
258 * For each program within the image file, load it, and
259 * record it's details. kernel, mm and fs must be loaded
260 * into the expected virtual addresses, so this is checked
261 * by minix_load for those programs.
262 */
263 base = (char *) memory_base;
264 for (prog = 0; prog < NUM_PROGS; prog++)
265 {
266 if (minix_load(fd, base, &bootp->prog[prog], prog != INIT_PROG) < 0) {
267 fprintf(stderr, "%s: Unable to load program %d\n", progname,
268 prog);
269 fprintf(stderr,
270 "\tRun make in src/tools to ensure that all ld map files are correct\n");
271 exit(1);
272 }
273
274 if (debug) {
275 (void) fprintf(stderr,
276 "Program %d, base 0x%x, t_size 0x%lx, d_size 0x%lx\n",
277 prog, (unsigned) base,
278 bootp->prog[prog].text_clicks << CLICK_SHIFT,
279 bootp->prog[prog].data_clicks << CLICK_SHIFT);
280 }
281 base += (bootp->prog[prog].text_clicks +
282 bootp->prog[prog].data_clicks) << CLICK_SHIFT;
283 }
284
285 return bootp; /* main() has more stuff to record as boot parameters */
286 }
287
288
289 /*
290 * Function: allocate_memory
291 * Parameters: memory_base - address to map memory in at
292 * ram_size - number of bytes to map
293 *
294 * We need to map a file in to act as smx memory because user programs
295 * need to be mapped into low memory. A temporary file is created,
296 * extended to the appropriate size, and mapped into memory. Files
297 * created by tmpfile are automatically deleted when the creating process
298 * exits. The smx kernel expects the file to be open on descriptor
299 * RAM_FD so that it can call mmap on it to run user programs.
300 */
301 static void allocate_memory(unsigned long memory_base, long ram_size)
302 {
303 char *ret_val;
304 FILE *mem_file = tmpfile();
305
306 if (mem_file == 0) {
307 fprintf(stderr, "%s: Unable to open RAM file\n", progname);
308 exit(1);
309 }
310 if (dup2(fileno(mem_file), RAM_FD) < 0) {
311 fprintf(stderr, "%s: Unable to dup RAM file fd\n", progname);
312 exit(1);
313 }
314 fclose(mem_file);
315
316 if (ftruncate(RAM_FD, ram_size) < 0) {
317 fprintf(stderr, "%s: Unable to size RAM\n", progname);
318 exit(1);
319 }
320 ret_val = mmap((char *)memory_base, ram_size,
321 PROT_READ | PROT_WRITE | PROT_EXEC,
322 MAP_SHARED | MAP_FIXED, RAM_FD, 0);
323 if (ret_val == MAP_FAILED) {
324 fprintf(stderr, "%s: Unable to map RAM file into memory\n", progname);
325 exit(1);
326 }
327 }
328
329
330 /*
331 * Function: smx_parent
332 *
333 * Code executed by the parent process after the fork. It blocks all
334 * but error signals while waiting for the child running smx to finish.
335 * Then it cleans up the smx devices and terminal settings and exits.
336 */
337 static void smx_parent(void)
338 {
339 sigset_t sigs;
340 int status;
341
342 sigfillset(&sigs);
343 sigdelset(&sigs, SIGILL);
344 sigdelset(&sigs, SIGTRAP);
345 sigdelset(&sigs, SIGEMT);
346 sigdelset(&sigs, SIGFPE);
347 sigdelset(&sigs, SIGBUS);
348 sigdelset(&sigs, SIGSEGV);
349 sigdelset(&sigs, SIGSYS);
350 (void) sigprocmask(SIG_SETMASK, &sigs, NULL);
351
352 wait(&status);
353
354 /*
355 * Tidy up smx device files and settings.
356 */
357 reset_devices();
358 exit(0);
359 }
360
361
362 /*
363 * Function: usage
364 */
365 static void usage(void)
366 {
367 fprintf(stderr, USAGE, progname);
368 exit(1);
369 }
370
371
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.