summaryrefslogtreecommitdiffstats
path: root/pintos-progos/threads/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/threads/init.c')
-rw-r--r--pintos-progos/threads/init.c453
1 files changed, 453 insertions, 0 deletions
diff --git a/pintos-progos/threads/init.c b/pintos-progos/threads/init.c
new file mode 100644
index 0000000..d8feacd
--- /dev/null
+++ b/pintos-progos/threads/init.c
@@ -0,0 +1,453 @@
1#include "threads/init.h"
2#include <console.h>
3#include <debug.h>
4#include <inttypes.h>
5#include <limits.h>
6#include <random.h>
7#include <stddef.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include "devices/kbd.h"
12#include "devices/input.h"
13#include "devices/serial.h"
14#include "devices/shutdown.h"
15#include "devices/timer.h"
16#include "devices/vga.h"
17#include "devices/rtc.h"
18#include "threads/interrupt.h"
19#include "threads/io.h"
20#include "threads/loader.h"
21#include "threads/malloc.h"
22#include "threads/palloc.h"
23#include "threads/pte.h"
24#include "threads/thread.h"
25#ifdef USERPROG
26#include "userprog/process.h"
27#include "userprog/exception.h"
28#include "userprog/gdt.h"
29#include "userprog/syscall.h"
30#include "userprog/tss.h"
31#else
32#include "tests/threads/tests.h"
33#endif
34#ifdef FILESYS
35#include "devices/block.h"
36#include "devices/ide.h"
37#include "filesys/filesys.h"
38#include "filesys/fsutil.h"
39#endif
40
41
42/* Page directory with kernel mappings only. */
43uint32_t *init_page_dir;
44
45#ifdef FILESYS
46/* -f: Format the file system? */
47static bool format_filesys;
48
49/* -filesys, -scratch, -swap: Names of block devices to use,
50 overriding the defaults. */
51static const char *filesys_bdev_name;
52static const char *scratch_bdev_name;
53#ifdef VM
54static const char *swap_bdev_name;
55#endif
56#endif /* FILESYS */
57
58/* -kernel-test: Run kernel test instead of user program */
59static bool kernel_test = false;
60
61/* provide weak kernel test definition if no test is available */
62void run_test (const char *param);
63__attribute__((weak))
64void
65run_test (const char *param UNUSED)
66{
67 printf("No kernel test linked into kernel\n");
68}
69
70
71/* -ul: Maximum number of pages to put into palloc's user pool. */
72static size_t user_page_limit = SIZE_MAX;
73
74static void bss_init (void);
75static void paging_init (void);
76
77static char **read_command_line (void);
78static char **parse_options (char **argv);
79static void run_actions (char **argv);
80static void usage (void);
81
82#ifdef FILESYS
83static void locate_block_devices (void);
84static void locate_block_device (enum block_type, const char *name);
85#endif
86
87int main (void) NO_RETURN;
88
89/* Pintos main program. */
90int
91main (void)
92{
93 char **argv;
94
95 /* Clear BSS. */
96 bss_init ();
97
98 /* Break command line into arguments and parse options. */
99 argv = read_command_line ();
100 argv = parse_options (argv);
101
102 /* Initialize ourselves as a thread so we can use locks,
103 then enable console locking. */
104 thread_init ();
105 console_init ();
106
107 /* Greet user. */
108 printf ("Pintos booting with %'"PRIu32" kB RAM...\n",
109 init_ram_pages * PGSIZE / 1024);
110
111 /* Initialize memory system. */
112 palloc_init (user_page_limit);
113 malloc_init ();
114 paging_init ();
115
116 /* Segmentation. */
117#ifdef USERPROG
118 tss_init ();
119 gdt_init ();
120#endif
121
122 /* Initialize interrupt handlers. */
123 intr_init ();
124 timer_init ();
125 kbd_init ();
126 input_init ();
127#ifdef USERPROG
128 exception_init ();
129 syscall_init ();
130#endif
131
132 /* Start thread scheduler and enable interrupts. */
133 thread_start ();
134 serial_init_queue ();
135 timer_calibrate ();
136
137#ifdef FILESYS
138 /* Initialize file system. */
139 ide_init ();
140 locate_block_devices ();
141 /* kernel tests do not need filesystem */
142 if (!kernel_test)
143 filesys_init (format_filesys);
144#endif
145
146 printf ("Boot complete.\n");
147
148 /* Run actions specified on kernel command line. */
149 run_actions (argv);
150
151 /* Finish up. */
152 shutdown ();
153 thread_exit ();
154}
155
156/* Clear the "BSS", a segment that should be initialized to
157 zeros. It isn't actually stored on disk or zeroed by the
158 kernel loader, so we have to zero it ourselves.
159
160 The start and end of the BSS segment is recorded by the
161 linker as _start_bss and _end_bss. See kernel.lds. */
162static void
163bss_init (void)
164{
165 extern char _start_bss, _end_bss;
166 memset (&_start_bss, 0, &_end_bss - &_start_bss);
167}
168
169/* Populates the base page directory and page table with the
170 kernel virtual mapping, and then sets up the CPU to use the
171 new page directory. Points init_page_dir to the page
172 directory it creates. */
173static void
174paging_init (void)
175{
176 uint32_t *pd, *pt;
177 size_t page;
178 extern char _start, _end_kernel_text;
179
180 pd = init_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
181 pt = NULL;
182 for (page = 0; page < init_ram_pages; page++)
183 {
184 uintptr_t paddr = page * PGSIZE;
185 char *vaddr = ptov (paddr);
186 size_t pde_idx = pd_no (vaddr);
187 size_t pte_idx = pt_no (vaddr);
188 bool in_kernel_text = &_start <= vaddr && vaddr < &_end_kernel_text;
189
190 if (pd[pde_idx] == 0)
191 {
192 pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
193 pd[pde_idx] = pde_create (pt);
194 }
195
196 pt[pte_idx] = pte_create_kernel (vaddr, !in_kernel_text);
197 }
198
199 /* Store the physical address of the page directory into CR3
200 aka PDBR (page directory base register). This activates our
201 new page tables immediately. See [IA32-v2a] "MOV--Move
202 to/from Control Registers" and [IA32-v3a] 3.7.5 "Base Address
203 of the Page Directory". */
204 asm volatile ("movl %0, %%cr3" : : "r" (vtop (init_page_dir)));
205}
206
207/* Breaks the kernel command line into words and returns them as
208 an argv-like array. */
209static char **
210read_command_line (void)
211{
212 static char *argv[LOADER_ARGS_LEN / 2 + 1];
213 char *p, *end;
214 int argc;
215 int i;
216
217 argc = *(uint32_t *) ptov (LOADER_ARG_CNT);
218 p = ptov (LOADER_ARGS);
219 end = p + LOADER_ARGS_LEN;
220 for (i = 0; i < argc; i++)
221 {
222 if (p >= end)
223 PANIC ("command line arguments overflow");
224
225 argv[i] = p;
226 p += strnlen (p, end - p) + 1;
227 }
228 argv[argc] = NULL;
229
230 /* Print kernel command line. */
231 printf ("Kernel command line:");
232 for (i = 0; i < argc; i++)
233 if (strchr (argv[i], ' ') == NULL)
234 printf (" %s", argv[i]);
235 else
236 printf (" '%s'", argv[i]);
237 printf ("\n");
238
239 return argv;
240}
241
242/* Parses options in ARGV[]
243 and returns the first non-option argument. */
244static char **
245parse_options (char **argv)
246{
247 for (; *argv != NULL && **argv == '-'; argv++)
248 {
249 char *save_ptr;
250 char *name = strtok_r (*argv, "=", &save_ptr);
251 char *value = strtok_r (NULL, "", &save_ptr);
252
253#ifndef USERPROG
254 kernel_test = true;
255#endif
256 if (!strcmp (name, "-h"))
257 usage ();
258 else if (!strcmp (name, "-q"))
259 shutdown_configure (SHUTDOWN_POWER_OFF);
260 else if (!strcmp (name, "-r"))
261 shutdown_configure (SHUTDOWN_REBOOT);
262#ifdef FILESYS
263 else if (!strcmp (name, "-f"))
264 format_filesys = true;
265 else if (!strcmp (name, "-filesys"))
266 filesys_bdev_name = value;
267 else if (!strcmp (name, "-scratch"))
268 scratch_bdev_name = value;
269#ifdef VM
270 else if (!strcmp (name, "-swap"))
271 swap_bdev_name = value;
272#endif
273#endif
274 else if (!strcmp (name, "-rs"))
275 random_init (atoi (value));
276 else if (!strcmp (name, "-mlfqs"))
277 thread_mlfqs = true;
278#ifdef USERPROG
279 else if (!strcmp (name, "-kernel-test"))
280 kernel_test = true;
281 else if (!strcmp (name, "-ul"))
282 user_page_limit = atoi (value);
283#endif
284 else
285 PANIC ("unknown option `%s' (use -h for help)", name);
286 }
287
288 /* Initialize the random number generator based on the system
289 time. This has no effect if an "-rs" option was specified.
290
291 When running under Bochs, this is not enough by itself to
292 get a good seed value, because the pintos script sets the
293 initial time to a predictable value, not to the local time,
294 for reproducibility. To fix this, give the "-r" option to
295 the pintos script to request real-time execution. */
296 random_init (rtc_get_time ());
297
298 return argv;
299}
300
301/* Runs the task specified in ARGV[1]. */
302static void
303run_task (char **argv)
304{
305 const char *task = argv[1];
306
307 printf ("Executing '%s':\n", task);
308#ifdef USERPROG
309 if (kernel_test)
310 run_test (task);
311 else
312 process_wait (process_execute (task));
313#else
314 run_test (task);
315#endif
316 printf ("Execution of '%s' complete.\n", task);
317}
318
319/* Executes all of the actions specified in ARGV[]
320 up to the null pointer sentinel. */
321static void
322run_actions (char **argv)
323{
324 /* An action. */
325 struct action
326 {
327 char *name; /* Action name. */
328 int argc; /* # of args, including action name. */
329 void (*function) (char **argv); /* Function to execute action. */
330 };
331
332 /* Table of supported actions. */
333 static const struct action actions[] =
334 {
335 {"run", 2, run_task},
336#ifdef FILESYS
337 {"ls", 1, fsutil_ls},
338 {"cat", 2, fsutil_cat},
339 {"rm", 2, fsutil_rm},
340 {"extract", 1, fsutil_extract},
341 {"append", 2, fsutil_append},
342#endif
343 {NULL, 0, NULL},
344 };
345
346 while (*argv != NULL)
347 {
348 const struct action *a;
349 int i;
350
351 /* Find action name. */
352 for (a = actions; ; a++)
353 if (a->name == NULL)
354 PANIC ("unknown action `%s' (use -h for help)", *argv);
355 else if (!strcmp (*argv, a->name))
356 break;
357
358 /* Check for required arguments. */
359 for (i = 1; i < a->argc; i++)
360 if (argv[i] == NULL)
361 PANIC ("action `%s' requires %d argument(s)", *argv, a->argc - 1);
362
363 /* Invoke action and advance. */
364 a->function (argv);
365 argv += a->argc;
366 }
367
368}
369
370/* Prints a kernel command line help message and powers off the
371 machine. */
372static void
373usage (void)
374{
375 printf ("\nCommand line syntax: [OPTION...] [ACTION...]\n"
376 "Options must precede actions.\n"
377 "Actions are executed in the order specified.\n"
378 "\nAvailable actions:\n"
379#ifdef USERPROG
380 " run 'PROG [ARG...]' Run PROG and wait for it to complete.\n"
381#else
382 " run TEST Run TEST.\n"
383#endif
384#ifdef FILESYS
385 " ls List files in the root directory.\n"
386 " cat FILE Print FILE to the console.\n"
387 " rm FILE Delete FILE.\n"
388 "Use these actions indirectly via `pintos' -g and -p options:\n"
389 " extract Untar from scratch device into file system.\n"
390 " append FILE Append FILE to tar file on scratch device.\n"
391#endif
392 "\nOptions:\n"
393 " -h Print this help message and power off.\n"
394 " -q Power off VM after actions or on panic.\n"
395 " -r Reboot after actions.\n"
396#ifdef FILESYS
397 " -f Format file system device during startup.\n"
398 " -filesys=BDEV Use BDEV for file system instead of default.\n"
399 " -scratch=BDEV Use BDEV for scratch instead of default.\n"
400#ifdef VM
401 " -swap=BDEV Use BDEV for swap instead of default.\n"
402#endif
403#endif
404 " -rs=SEED Set random number seed to SEED.\n"
405 " -mlfqs Use multi-level feedback queue scheduler.\n"
406#ifdef USERPROG
407 " -ul=COUNT Limit user memory to COUNT pages.\n"
408#endif
409 );
410 shutdown_power_off ();
411}
412
413#ifdef FILESYS
414/* Figure out what block devices to cast in the various Pintos roles. */
415static void
416locate_block_devices (void)
417{
418 locate_block_device (BLOCK_FILESYS, filesys_bdev_name);
419 locate_block_device (BLOCK_SCRATCH, scratch_bdev_name);
420#ifdef VM
421 locate_block_device (BLOCK_SWAP, swap_bdev_name);
422#endif
423}
424
425/* Figures out what block device to use for the given ROLE: the
426 block device with the given NAME, if NAME is non-null,
427 otherwise the first block device in probe order of type
428 ROLE. */
429static void
430locate_block_device (enum block_type role, const char *name)
431{
432 struct block *block = NULL;
433
434 if (name != NULL)
435 {
436 block = block_get_by_name (name);
437 if (block == NULL)
438 PANIC ("No such block device \"%s\"", name);
439 }
440 else
441 {
442 for (block = block_first (); block != NULL; block = block_next (block))
443 if (block_type (block) == role)
444 break;
445 }
446
447 if (block != NULL)
448 {
449 printf ("%s: using %s\n", block_type_name (role), block_name (block));
450 block_set_role (role, block);
451 }
452}
453#endif