Remove call to sema_self_test() from main().
[pintos-anon] / src / threads / init.c
1 #include <stdint.h>
2 #include <stddef.h>
3 #include <limits.h>
4 #include "debug.h"
5 #include "interrupt.h"
6 #include "io.h"
7 #include "kbd.h"
8 #include "lib.h"
9 #include "malloc.h"
10 #include "mmu.h"
11 #include "palloc.h"
12 #include "random.h"
13 #include "serial.h"
14 #include "thread.h"
15 #include "timer.h"
16 #include "vga.h"
17 #ifdef FILESYS
18 #include "filesys.h"
19 #endif
20
21 /* Size of kernel static code and data, in 4 kB pages. */
22 size_t kernel_pages;
23
24 /* Amount of physical memory, in 4 kB pages. */
25 size_t ram_pages;
26
27 static void init_page_table (void);
28 static void setup_gdt (void);
29 void power_off (void);
30
31 struct thread *a, *b;
32
33 static void
34 tfunc (void *aux UNUSED) 
35 {
36   for (;;) 
37     {
38       size_t count, i;
39       if (random_ulong () % 5 == 0)
40         {
41           printk ("%s exiting\n", thread_current ()->name);
42           break;
43         }
44       count = random_ulong () % 25 * 10000;
45       printk ("%s waiting %zu: ", thread_current ()->name, count);
46       for (i = 0; i < count; i++);
47       printk ("%s\n", thread_current ()->name);
48     }
49 }
50
51 int
52 main (void)
53 {
54   extern char _text, _end, __bss_start;
55
56   /* Clear out the BSS segment. */
57   memset (&__bss_start, 0, &_end - &__bss_start);
58
59   vga_init ();
60   serial_init ();
61
62   /* Calculate how much RAM the kernel uses, and find out from
63      the bootloader how much RAM this machine has. */
64   kernel_pages = (&_end - &_text + 4095) / 4096;
65   ram_pages = *(uint32_t *) (0x7e00 - 8);
66
67   printk ("Initializing nachos-x86, %d kB RAM detected.\n",
68           ram_pages * 4);
69
70   /* Memory from the end of the kernel through the end of memory
71      is free.  Give it to the page allocator. */
72   palloc_init ((void *) (KERN_BASE + kernel_pages * NBPG),
73                (void *) (PHYS_BASE + ram_pages * NBPG));
74
75   init_page_table ();
76   setup_gdt ();
77
78   malloc_init ();
79   random_init ();
80
81   intr_init ();
82   timer_init ();
83   kbd_init ();
84
85 #ifdef FILESYS
86   filesys_init (false);
87 #endif
88
89   thread_init ();
90
91   {
92     struct thread *t;
93     int i;
94     
95     for (i = 0; i < 4; i++) 
96       {
97         char name[2];
98         name[0] = 'a' + i;
99         name[1] = 0;
100         t = thread_create (name, tfunc, NULL); 
101       }
102     thread_start (t); 
103   }
104
105   printk ("Done!\n");
106   return 0;
107 }
108
109 /* Populates the page directory and page table with the kernel
110    virtual mapping. */
111 static void
112 init_page_table (void)
113 {
114   uint32_t *pd, *pt;
115   uint32_t paddr;
116
117   pd = palloc_get (PAL_ASSERT | PAL_ZERO);
118   pt = NULL;
119   for (paddr = 0; paddr < NBPG * ram_pages; paddr += NBPG)
120     {
121       uint32_t vaddr = paddr + PHYS_BASE;
122       size_t pde_idx = PDENO(vaddr);
123       size_t pte_idx = PTENO(vaddr);
124
125       if (pd[pde_idx] == 0)
126         {
127           pt = palloc_get (PAL_ASSERT | PAL_ZERO);
128           pd[pde_idx] = (uint32_t) vtop (pt) | PG_U | PG_W | PG_P;
129         }
130
131       pt[pte_idx] = paddr | PG_U | PG_W | PG_P;
132     }
133
134   /* Set the page table. */
135   asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
136 }
137
138 static uint64_t
139 make_seg_desc (uint32_t base,
140                uint32_t limit,
141                enum seg_system system,
142                enum seg_type type,
143                int dpl,
144                enum seg_granularity granularity)
145 {
146   uint32_t e0 = ((limit & 0xffff)             /* Limit 15:0. */
147                  | (base << 16));             /* Base 15:0. */
148   uint32_t e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
149                  | ( system << 12)  /* 0=system, 1=code/data. */
150                  | ( type << 8)     /* Segment type. */
151                  | (dpl << 13)                /* Descriptor privilege. */
152                  | (1 << 15)                  /* Present. */
153                  | (limit & 0xf0000)          /* Limit 16:19. */
154                  | (1 << 22)                  /* 32-bit segment. */
155                  | ( granularity << 23) /* Byte/page granularity. */
156                  | (base & 0xff000000));      /* Base 31:24. */
157   return e0 | ((uint64_t) e1 << 32);
158 }
159
160 static uint64_t
161 make_code_desc (int dpl)
162 {
163   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
164                         dpl, GRAN_PAGE);
165 }
166
167 static uint64_t
168 make_data_desc (int dpl)
169 {
170   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
171                         dpl, GRAN_PAGE);
172 }
173
174 static uint64_t
175 make_tss_desc (uint32_t base)
176 {
177   return make_seg_desc (base, 0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
178 }
179
180 uint64_t gdt[SEL_CNT];
181
182 struct tss *tss;
183
184 /* Sets up a proper GDT.  The bootstrap loader's GDT didn't
185    include user-mode selectors or a TSS. */
186 static void
187 setup_gdt (void)
188 {
189   uint64_t gdtr_operand;
190
191   /* Our TSS is never used in a call gate or task gate, so only a
192      few fields of it are ever referenced, and those are the only
193      ones we initialize. */
194   tss = palloc_get (PAL_ASSERT | PAL_ZERO);
195   tss->esp0 = (uint32_t) ptov(0xc0020000);
196   tss->ss0 = SEL_KDSEG;
197   tss->bitmap = 0xdfff;
198
199   /* Initialize GDT. */
200   gdt[SEL_NULL / sizeof *gdt] = 0;
201   gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
202   gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
203   gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
204   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
205   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (vtop (tss));
206
207   /* Load GDTR, TR. */
208   gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
209   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
210   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
211 }
212 \f
213 void
214 power_off (void) 
215 {
216   const char s[] = "Shutdown";
217   const char *p;
218
219   printk ("Powering off...\n");
220   for (p = s; *p != '\0'; p++)
221     outb (0x8900, *p);
222   for (;;);
223 }