Working backdoor filesystem implementation.
[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 #if 0
92   printk ("running semaphore test...  ");
93   sema_self_test ();
94   printk ("  done.\n");
95 #endif
96
97   {
98     struct thread *t;
99     int i;
100     
101     for (i = 0; i < 4; i++) 
102       {
103         char name[2];
104         name[0] = 'a' + i;
105         name[1] = 0;
106         t = thread_create (name, tfunc, NULL); 
107       }
108     thread_start (t); 
109   }
110
111   printk ("Done!\n");
112   return 0;
113 }
114
115 /* Populates the page directory and page table with the kernel
116    virtual mapping. */
117 static void
118 init_page_table (void)
119 {
120   uint32_t *pd, *pt;
121   uint32_t paddr;
122
123   pd = palloc_get (PAL_ASSERT | PAL_ZERO);
124   pt = NULL;
125   for (paddr = 0; paddr < NBPG * ram_pages; paddr += NBPG)
126     {
127       uint32_t vaddr = paddr + PHYS_BASE;
128       size_t pde_idx = PDENO(vaddr);
129       size_t pte_idx = PTENO(vaddr);
130
131       if (pd[pde_idx] == 0)
132         {
133           pt = palloc_get (PAL_ASSERT | PAL_ZERO);
134           pd[pde_idx] = (uint32_t) vtop (pt) | PG_U | PG_W | PG_P;
135         }
136
137       pt[pte_idx] = paddr | PG_U | PG_W | PG_P;
138     }
139
140   /* Set the page table. */
141   asm volatile ("movl %0,%%cr3" :: "r" (vtop (pd)));
142 }
143
144 static uint64_t
145 make_seg_desc (uint32_t base,
146                uint32_t limit,
147                enum seg_system system,
148                enum seg_type type,
149                int dpl,
150                enum seg_granularity granularity)
151 {
152   uint32_t e0 = ((limit & 0xffff)             /* Limit 15:0. */
153                  | (base << 16));             /* Base 15:0. */
154   uint32_t e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
155                  | ( system << 12)  /* 0=system, 1=code/data. */
156                  | ( type << 8)     /* Segment type. */
157                  | (dpl << 13)                /* Descriptor privilege. */
158                  | (1 << 15)                  /* Present. */
159                  | (limit & 0xf0000)          /* Limit 16:19. */
160                  | (1 << 22)                  /* 32-bit segment. */
161                  | ( granularity << 23) /* Byte/page granularity. */
162                  | (base & 0xff000000));      /* Base 31:24. */
163   return e0 | ((uint64_t) e1 << 32);
164 }
165
166 static uint64_t
167 make_code_desc (int dpl)
168 {
169   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
170                         dpl, GRAN_PAGE);
171 }
172
173 static uint64_t
174 make_data_desc (int dpl)
175 {
176   return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
177                         dpl, GRAN_PAGE);
178 }
179
180 static uint64_t
181 make_tss_desc (uint32_t base)
182 {
183   return make_seg_desc (base, 0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
184 }
185
186 uint64_t gdt[SEL_CNT];
187
188 struct tss *tss;
189
190 /* Sets up a proper GDT.  The bootstrap loader's GDT didn't
191    include user-mode selectors or a TSS. */
192 static void
193 setup_gdt (void)
194 {
195   uint64_t gdtr_operand;
196
197   /* Our TSS is never used in a call gate or task gate, so only a
198      few fields of it are ever referenced, and those are the only
199      ones we initialize. */
200   tss = palloc_get (PAL_ASSERT | PAL_ZERO);
201   tss->esp0 = (uint32_t) ptov(0xc0020000);
202   tss->ss0 = SEL_KDSEG;
203   tss->bitmap = 0xdfff;
204
205   /* Initialize GDT. */
206   gdt[SEL_NULL / sizeof *gdt] = 0;
207   gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
208   gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
209   gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
210   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
211   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (vtop (tss));
212
213   /* Load GDTR, TR. */
214   gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
215   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
216   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
217 }
218 \f
219 void
220 power_off (void) 
221 {
222   const char s[] = "Shutdown";
223   const char *p;
224
225   printk ("Powering off...\n");
226   for (p = s; *p != '\0'; p++)
227     outb (0x8900, *p);
228   for (;;);
229 }