schedule the highest priority thread,overP1
[monosproject.git] / src / threads / init.c
blob8086d317b4826ffe96607b0eeee4a1a63abd455f
1 #include "threads/init.h"
2 #include <console.h>
3 #include <debug.h>
4 #include <limits.h>
5 #include <random.h>
6 #include <stddef.h>
7 #include <stdint.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/timer.h"
15 #include "devices/vga.h"
16 #include "threads/interrupt.h"
17 #include "threads/io.h"
18 #include "threads/loader.h"
19 #include "threads/malloc.h"
20 #include "threads/palloc.h"
21 #include "threads/pte.h"
22 #include "threads/thread.h"
23 #ifdef USERPROG
24 #include "userprog/process.h"
25 #include "userprog/exception.h"
26 #include "userprog/gdt.h"
27 #include "userprog/syscall.h"
28 #include "userprog/tss.h"
29 #else
30 #include "tests/threads/tests.h"
31 #endif
32 #ifdef FILESYS
33 #include "devices/disk.h"
34 #include "filesys/filesys.h"
35 #include "filesys/fsutil.h"
36 #endif
38 /* Amount of physical memory, in 4 kB pages. */
39 size_t ram_pages;
41 /* Page directory with kernel mappings only. */
42 uint32_t *base_page_dir;
44 #ifdef FILESYS
45 /* -f: Format the file system? */
46 static bool format_filesys;
47 #endif
49 /* -q: Power off after kernel tasks complete? */
50 bool power_off_when_done;
52 static void ram_init (void);
53 static void paging_init (void);
55 static char **read_command_line (void);
56 static char **parse_options (char **argv);
57 static void run_actions (char **argv);
58 static void usage (void);
60 static void print_stats (void);
63 int main (void) NO_RETURN;
65 /* Pintos main program. */
66 int
67 main (void)
69 char **argv;
71 /* Clear BSS and get machine's RAM size. */
72 ram_init ();
74 /* Break command line into arguments and parse options. */
75 argv = read_command_line ();
76 argv = parse_options (argv);
78 /* Initialize ourselves as a thread so we can use locks,
79 then enable console locking. */
80 thread_init ();
81 console_init ();
83 /* Greet user. */
84 printf ("Pintos booting with %'zu kB RAM...\n", ram_pages * PGSIZE / 1024);
86 /* Initialize memory system. */
87 palloc_init ();
88 malloc_init ();
89 paging_init ();
91 /* Segmentation. */
92 #ifdef USERPROG
93 tss_init ();
94 gdt_init ();
95 #endif
97 /* Initialize interrupt handlers. */
98 intr_init ();
99 timer_init ();
100 kbd_init ();
101 input_init ();
102 #ifdef USERPROG
103 exception_init ();
104 syscall_init ();
105 #endif
106 /* Start thread scheduler and enable interrupts. */
107 thread_start ();
108 serial_init_queue ();
109 timer_calibrate ();
111 #ifdef FILESYS
112 /* Initialize file system. */
113 disk_init ();
114 filesys_init (format_filesys);
115 #endif
117 printf ("Boot complete.\n");
118 // timer_sleep(1000);
120 /* Run actions specified on kernel command line. */
121 run_actions (argv);
123 /* Finish up. */
124 if (power_off_when_done)
125 power_off ();
126 thread_exit ();
129 /* Clear BSS and obtain RAM size from loader. */
130 static void
131 ram_init (void)
133 /* The "BSS" is a segment that should be initialized to zeros.
134 It isn't actually stored on disk or zeroed by the kernel
135 loader, so we have to zero it ourselves.
137 The start and end of the BSS segment is recorded by the
138 linker as _start_bss and _end_bss. See kernel.lds. */
139 extern char _start_bss, _end_bss;
140 memset (&_start_bss, 0, &_end_bss - &_start_bss);
142 /* Get RAM size from loader. See loader.S. */
143 ram_pages = *(uint32_t *) ptov (LOADER_RAM_PGS);
146 /* Populates the base page directory and page table with the
147 kernel virtual mapping, and then sets up the CPU to use the
148 new page directory. Points base_page_dir to the page
149 directory it creates.
151 At the time this function is called, the active page table
152 (set up by loader.S) only maps the first 4 MB of RAM, so we
153 should not try to use extravagant amounts of memory.
154 Fortunately, there is no need to do so. */
155 static void
156 paging_init (void)
158 uint32_t *pd, *pt;
159 size_t page;
160 extern char _start, _end_kernel_text;
162 pd = base_page_dir = palloc_get_page (PAL_ASSERT | PAL_ZERO);
163 pt = NULL;
164 for (page = 0; page < ram_pages; page++)
166 uintptr_t paddr = page * PGSIZE;
167 char *vaddr = ptov (paddr);
168 size_t pde_idx = pd_no (vaddr);
169 size_t pte_idx = pt_no (vaddr);
170 bool in_kernel_text = &_start <= vaddr && vaddr < &_end_kernel_text;
172 if (pd[pde_idx] == 0)
174 pt = palloc_get_page (PAL_ASSERT | PAL_ZERO);
175 pd[pde_idx] = pde_create (pt);
178 pt[pte_idx] = pte_create_kernel (vaddr, !in_kernel_text);
181 /* Store the physical address of the page directory into CR3
182 aka PDBR (page directory base register). This activates our
183 new page tables immediately. See [IA32-v2a] "MOV--Move
184 to/from Control Registers" and [IA32-v3a] 3.7.5 "Base Address
185 of the Page Directory". */
186 asm volatile ("movl %0, %%cr3" : : "r" (vtop (base_page_dir)));
189 /* Breaks the kernel command line into words and returns them as
190 an argv-like array. */
191 static char **
192 read_command_line (void)
194 static char *argv[LOADER_ARGS_LEN / 2 + 1];
195 char *p, *end;
196 int argc;
197 int i;
199 argc = *(uint32_t *) ptov (LOADER_ARG_CNT);
200 p = ptov (LOADER_ARGS);
201 end = p + LOADER_ARGS_LEN;
202 for (i = 0; i < argc; i++)
204 if (p >= end)
205 PANIC ("command line arguments overflow");
207 argv[i] = p;
208 p += strnlen (p, end - p) + 1;
210 argv[argc] = NULL;
212 /* Print kernel command line. */
213 printf ("Kernel command line:");
214 for (i = 0; i < argc; i++)
215 if (strchr (argv[i], ' ') == NULL)
216 printf (" %s", argv[i]);
217 else
218 printf (" '%s'", argv[i]);
219 printf ("\n");
221 return argv;
224 /* Parses options in ARGV[]
225 and returns the first non-option argument. */
226 static char **
227 parse_options (char **argv)
229 for (; *argv != NULL && **argv == '-'; argv++)
231 char *save_ptr;
232 char *name = strtok_r (*argv, "=", &save_ptr);
233 char *value = strtok_r (NULL, "", &save_ptr);
235 if (!strcmp (name, "-h"))
236 usage ();
237 else if (!strcmp (name, "-q"))
238 power_off_when_done = true;
239 #ifdef FILESYS
240 else if (!strcmp (name, "-f"))
241 format_filesys = true;
242 #endif
243 else if (!strcmp (name, "-rs"))
244 random_init (atoi (value));
245 else if (!strcmp (name, "-mlfqs"))
246 thread_mlfqs = true;
247 #ifdef USERPROG
248 else if (!strcmp (name, "-ul"))
249 user_page_limit = atoi (value);
250 #endif
251 else
252 PANIC ("unknown option `%s' (use -h for help)", name);
255 return argv;
258 /* Runs the task specified in ARGV[1]. */
259 static void
260 run_task (char **argv)
262 const char *task = argv[1];
264 printf ("Executing '%s':\n", task);
265 #ifdef USERPROG
266 process_wait (process_execute (task));
267 #else
268 run_test (task);
269 #endif
270 printf ("Execution of '%s' complete.\n", task);
273 /* Executes all of the actions specified in ARGV[]
274 up to the null pointer sentinel. */
275 static void
276 run_actions (char **argv)
278 /* An action. */
279 struct action
281 char *name; /* Action name. */
282 int argc; /* # of args, including action name. */
283 void (*function) (char **argv); /* Function to execute action. */
286 /* Table of supported actions. */
287 static const struct action actions[] =
289 {"run", 2, run_task},
290 #ifdef FILESYS
291 {"ls", 1, fsutil_ls},
292 {"cat", 2, fsutil_cat},
293 {"rm", 2, fsutil_rm},
294 {"put", 2, fsutil_put},
295 {"get", 2, fsutil_get},
296 #endif
297 {NULL, 0, NULL},
300 while (*argv != NULL)
302 const struct action *a;
303 int i;
305 /* Find action name. */
306 for (a = actions; ; a++)
307 if (a->name == NULL)
308 PANIC ("unknown action `%s' (use -h for help)", *argv);
309 else if (!strcmp (*argv, a->name))
310 break;
312 /* Check for required arguments. */
313 for (i = 1; i < a->argc; i++)
314 if (argv[i] == NULL)
315 PANIC ("action `%s' requires %d argument(s)", *argv, a->argc - 1);
317 /* Invoke action and advance. */
318 a->function (argv);
319 argv += a->argc;
324 /* Prints a kernel command line help message and powers off the
325 machine. */
326 static void
327 usage (void)
329 printf ("\nCommand line syntax: [OPTION...] [ACTION...]\n"
330 "Options must precede actions.\n"
331 "Actions are executed in the order specified.\n"
332 "\nAvailable actions:\n"
333 #ifdef USERPROG
334 " run 'PROG [ARG...]' Run PROG and wait for it to complete.\n"
335 #else
336 " run TEST Run TEST.\n"
337 #endif
338 #ifdef FILESYS
339 " ls List files in the root directory.\n"
340 " cat FILE Print FILE to the console.\n"
341 " rm FILE Delete FILE.\n"
342 "Use these actions indirectly via `pintos' -g and -p options:\n"
343 " put FILE Put FILE into file system from scratch disk.\n"
344 " get FILE Get FILE from file system into scratch disk.\n"
345 #endif
346 "\nOptions:\n"
347 " -h Print this help message and power off.\n"
348 " -q Power off VM after actions or on panic.\n"
349 " -f Format file system disk during startup.\n"
350 " -rs=SEED Set random number seed to SEED.\n"
351 " -mlfqs Use multi-level feedback queue scheduler.\n"
352 #ifdef USERPROG
353 " -ul=COUNT Limit user memory to COUNT pages.\n"
354 #endif
356 power_off ();
360 /* Powers down the machine we're running on,
361 as long as we're running on Bochs or QEMU. */
362 void
363 power_off (void)
365 const char s[] = "Shutdown";
366 const char *p;
368 #ifdef FILESYS
369 filesys_done ();
370 #endif
372 print_stats ();
374 printf ("Powering off...\n");
375 serial_flush ();
377 for (p = s; *p != '\0'; p++)
378 outb (0x8900, *p);
379 asm volatile ("cli; hlt" : : : "memory");
380 printf ("still running...\n");
381 for (;;);
384 /* Print statistics about Pintos execution. */
385 static void
386 print_stats (void)
388 timer_print_stats ();
389 thread_print_stats ();
390 #ifdef FILESYS
391 disk_print_stats ();
392 #endif
393 console_print_stats ();
394 kbd_print_stats ();
395 #ifdef USERPROG
396 exception_print_stats ();
397 #endif