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