Clean up threads.c.
[pintos-anon] / src / threads / init.c
1 #include "init.h"
2 #include <stdint.h>
3 #include <stddef.h>
4 #include <limits.h>
5 #include "debug.h"
6 #include "interrupt.h"
7 #include "io.h"
8 #include "kbd.h"
9 #include "lib.h"
10 #include "loader.h"
11 #include "malloc.h"
12 #include "mmu.h"
13 #include "paging.h"
14 #include "palloc.h"
15 #include "random.h"
16 #include "serial.h"
17 #include "thread.h"
18 #include "timer.h"
19 #include "vga.h"
20 #ifdef FILESYS
21 #include "filesys.h"
22 #include "disk.h"
23 #endif
24
25 /* Amount of physical memory, in 4 kB pages. */
26 size_t ram_pages;
27
28 static void ram_init (void);
29 static void gdt_init (void);
30 static void argv_init (void);
31
32 static void
33 main_thread (void *aux UNUSED) 
34 {
35 #ifdef FILESYS
36   disk_init ();
37   filesys_init (true);
38   filesys_self_test ();
39 #endif
40 }
41
42 int
43 main (void)
44 {
45   /* Initialize prerequisites for calling printk(). */
46   ram_init ();
47   vga_init ();
48   serial_init ();
49
50   /* Greet user. */
51   printk ("Booting cnachos86 with %'d kB RAM...\n", ram_pages * 4);
52
53   /* Initialize memory system. */
54   palloc_init ();
55   paging_init ();
56   gdt_init ();
57   malloc_init ();
58
59   random_init ();
60   argv_init ();
61
62   /* Initialize interrupt handlers. */
63   intr_init ();
64   timer_init ();
65   kbd_init ();
66
67   /* Do everything else in a system thread. */
68   thread_init ("main", main_thread, NULL);
69 }
70
71 static uint64_t
72 make_seg_desc (uint32_t base,
73                uint32_t limit,
74                enum seg_system system,
75                enum seg_type type,
76                int dpl,
77                enum seg_granularity granularity)
78 {
79   uint32_t e0 = ((limit & 0xffff)             /* Limit 15:0. */
80                  | (base << 16));             /* Base 15:0. */
81   uint32_t e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
82                  | (system << 12)             /* 0=system, 1=code/data. */
83                  | (type << 8)                /* Segment type. */
84                  | (dpl << 13)                /* Descriptor privilege. */
85                  | (1 << 15)                  /* Present. */
86                  | (limit & 0xf0000)          /* Limit 16:19. */
87                  | (1 << 22)                  /* 32-bit segment. */
88                  | (granularity << 23)        /* Byte/page granularity. */
89                  | (base & 0xff000000));      /* Base 31:24. */
90   return e0 | ((uint64_t) e1 << 32);
91 }
92
93 static uint64_t
94 make_code_desc (int dpl)
95 {
96   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
97                         dpl, GRAN_PAGE);
98 }
99
100 static uint64_t
101 make_data_desc (int dpl)
102 {
103   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
104                         dpl, GRAN_PAGE);
105 }
106
107 static uint64_t
108 make_tss_desc (void *vaddr)
109 {
110   return make_seg_desc ((uint32_t) vaddr,
111                         0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
112 }
113
114 static uint64_t gdt[SEL_CNT];
115
116 struct tss *tss;
117
118 /* Sets up a proper GDT.  The bootstrap loader's GDT didn't
119    include user-mode selectors or a TSS. */
120 static void
121 gdt_init (void)
122 {
123   uint64_t gdtr_operand;
124
125   /* Our TSS is never used in a call gate or task gate, so only a
126      few fields of it are ever referenced, and those are the only
127      ones we initialize. */
128   tss = palloc_get (PAL_ASSERT | PAL_ZERO);
129   tss->esp0 = (uint32_t) ptov(0x20000);
130   tss->ss0 = SEL_KDSEG;
131   tss->bitmap = 0xdfff;
132
133   /* Initialize GDT. */
134   gdt[SEL_NULL / sizeof *gdt] = 0;
135   gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
136   gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
137   gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
138   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
139   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
140
141   /* Load GDTR, TR. */
142   gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
143   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
144   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
145 }
146
147 static void
148 ram_init (void) 
149 {
150   /* The "BSS" is a segment that should be initialized to zeros.
151      It isn't actually stored on disk or zeroed by the kernel
152      loader, so we have to zero it ourselves.
153
154      The start and end of the BSS segment is recorded by the
155      linker as _start_bss and _end_bss.  See kernel.lds. */
156   extern char _start_bss, _end_bss;
157   memset (&_start_bss, 0, &_end_bss - &_start_bss);
158
159   /* Get RAM size from loader. */
160   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
161 }
162 \f
163 /* This should be sufficient because the command line buffer is
164    only 128 bytes and arguments are space-delimited. */
165 #define ARGC_MAX 64
166
167 int argc;
168 char *argv[ARGC_MAX + 1];
169
170 static void
171 argv_init (void) 
172 {
173   char *cmd_line = ptov (LOADER_CMD_LINE);
174   char *arg, *pos;
175
176   for (arg = strtok_r (cmd_line, " \t\r\n\v", &pos); arg != NULL;
177        arg = strtok_r (NULL, " \t\r\n\v", &pos))
178     {
179       ASSERT (argc < ARGC_MAX);
180       argv[argc++] = arg;
181     }
182   argv[argc] = NULL;
183 }