Clean up disk layer.
[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 #include "fsutil.h"
24 #endif
25
26 /* Amount of physical memory, in 4 kB pages. */
27 size_t ram_pages;
28
29 #ifdef FILESYS
30 /* Format the filesystem? */
31 static bool format_filesys;
32 #endif
33
34 #ifdef USERPROG
35 /* Initial program to run. */
36 static char *initial_program;
37 #endif
38
39 static void ram_init (void);
40 static void gdt_init (void);
41 static void argv_init (void);
42
43 static void
44 main_thread (void *aux UNUSED) 
45 {
46 #ifdef FILESYS
47   disk_init ();
48   filesys_init (format_filesys);
49   fsutil_run ();
50 #endif
51
52 #ifdef USERPROG
53   if (initial_program != NULL)
54     thread_execute (initial_program);
55   else
56     PANIC ("no initial program specified");
57 #endif
58 }
59
60 int
61 main (void)
62 {
63   /* Initialize prerequisites for calling printk(). */
64   ram_init ();
65   vga_init ();
66   serial_init ();
67
68   /* Greet user. */
69   printk ("Booting cnachos86 with %'d kB RAM...\n", ram_pages * 4);
70
71   /* Parse command line. */
72   argv_init ();
73
74   /* Initialize memory system. */
75   palloc_init ();
76   paging_init ();
77   gdt_init ();
78   malloc_init ();
79
80   random_init (0);
81
82   /* Initialize interrupt handlers. */
83   intr_init ();
84   timer_init ();
85   kbd_init ();
86
87   /* Do everything else in a system thread. */
88   thread_init ();
89   thread_create ("main", main_thread, NULL);
90   thread_start ();
91 }
92
93 static uint64_t
94 make_seg_desc (uint32_t base,
95                uint32_t limit,
96                enum seg_system system,
97                enum seg_type type,
98                int dpl,
99                enum seg_granularity granularity)
100 {
101   uint32_t e0 = ((limit & 0xffff)             /* Limit 15:0. */
102                  | (base << 16));             /* Base 15:0. */
103   uint32_t e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
104                  | (system << 12)             /* 0=system, 1=code/data. */
105                  | (type << 8)                /* Segment type. */
106                  | (dpl << 13)                /* Descriptor privilege. */
107                  | (1 << 15)                  /* Present. */
108                  | (limit & 0xf0000)          /* Limit 16:19. */
109                  | (1 << 22)                  /* 32-bit segment. */
110                  | (granularity << 23)        /* Byte/page granularity. */
111                  | (base & 0xff000000));      /* Base 31:24. */
112   return e0 | ((uint64_t) e1 << 32);
113 }
114
115 static uint64_t
116 make_code_desc (int dpl)
117 {
118   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
119                         dpl, GRAN_PAGE);
120 }
121
122 static uint64_t
123 make_data_desc (int dpl)
124 {
125   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
126                         dpl, GRAN_PAGE);
127 }
128
129 static uint64_t
130 make_tss_desc (void *vaddr)
131 {
132   return make_seg_desc ((uint32_t) vaddr,
133                         0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
134 }
135
136 static uint64_t gdt[SEL_CNT];
137
138 struct tss *tss;
139
140 /* Sets up a proper GDT.  The bootstrap loader's GDT didn't
141    include user-mode selectors or a TSS. */
142 static void
143 gdt_init (void)
144 {
145   uint64_t gdtr_operand;
146
147   /* Our TSS is never used in a call gate or task gate, so only a
148      few fields of it are ever referenced, and those are the only
149      ones we initialize. */
150   tss = palloc_get (PAL_ASSERT | PAL_ZERO);
151   tss->esp0 = (uint32_t) ptov(0x20000);
152   tss->ss0 = SEL_KDSEG;
153   tss->bitmap = 0xdfff;
154
155   /* Initialize GDT. */
156   gdt[SEL_NULL / sizeof *gdt] = 0;
157   gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
158   gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
159   gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
160   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
161   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
162
163   /* Load GDTR, TR. */
164   gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
165   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
166   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
167 }
168
169 static void
170 ram_init (void) 
171 {
172   /* The "BSS" is a segment that should be initialized to zeros.
173      It isn't actually stored on disk or zeroed by the kernel
174      loader, so we have to zero it ourselves.
175
176      The start and end of the BSS segment is recorded by the
177      linker as _start_bss and _end_bss.  See kernel.lds. */
178   extern char _start_bss, _end_bss;
179   memset (&_start_bss, 0, &_end_bss - &_start_bss);
180
181   /* Get RAM size from loader. */
182   ram_pages = *(uint32_t *) ptov (LOADER_RAM_PAGES);
183 }
184 \f
185 static void
186 argv_init (void) 
187 {
188   char *cmd_line, *pos;
189   char *argv[LOADER_CMD_LINE_LEN / 2 + 1];
190   int argc = 0;
191   int i;
192
193   /* The command line is made up of null terminated strings
194      followed by an empty string.  Break it up into words. */
195   cmd_line = pos = ptov (LOADER_CMD_LINE);
196   while (pos < cmd_line + LOADER_CMD_LINE_LEN)
197     {
198       ASSERT (argc < LOADER_CMD_LINE_LEN / 2);
199       if (*pos == '\0')
200         break;
201       argv[argc++] = pos;
202       pos = strchr (pos, '\0') + 1;
203     }
204   argv[argc] = "";
205
206   /* Parse the words. */
207   for (i = 0; i < argc; i++)
208     if (!strcmp (argv[i], "-rs")) 
209       random_init (atoi (argv[++i]));
210     else if (!strcmp (argv[i], "-d")) 
211       debug_enable (argv[++i]);
212 #ifdef USERPROG
213     else if (!strcmp (argv[i], "-ex")) 
214       initial_program = argv[++i];
215 #endif
216 #ifdef FILESYS
217   else if (!strcmp (argv[i], "-f"))
218       format_filesys = true;
219     else if (!strcmp (argv[i], "-cp")) 
220       fsutil_copy_arg = argv[++i];
221     else if (!strcmp (argv[i], "-p")) 
222       fsutil_print_file = argv[++i];
223     else if (!strcmp (argv[i], "-r"))
224       fsutil_remove_file = argv[++i];
225     else if (!strcmp (argv[i], "-ls"))
226       fsutil_list_files = true;
227     else if (!strcmp (argv[i], "-D"))
228       fsutil_dump_filesys = true;
229 #endif
230     else if (!strcmp (argv[i], "-u"))
231       {
232         printk (
233           "Kernel options:\n"
234           " -rs SEED            Seed random seed to SEED.\n"
235           " -d CLASS[,...]      Enable the given classes of debug messages.\n"
236 #ifdef USERPROG
237           " -ex 'PROG [ARG...]' Run PROG, passing the optional arguments.\n"
238 #endif
239 #ifdef FILESYS
240           " -f                  Format the filesystem disk (hdb or hd0:1).\n"
241           " -cp FILENAME:SIZE   Copy SIZE bytes from the scratch disk (hdc\n"
242           "                     or hd1:0) into the filesystem as FILENAME\n"
243           " -p FILENAME         Print the contents of FILENAME\n"
244           " -r FILENAME         Delete FILENAME\n"
245           " -ls                 List the files in the filesystem\n"
246           " -D                  Dump complete filesystem contents\n");
247 #endif
248       }
249     else 
250       PANIC ("unknown option `%s'", argv[i]);
251 }