1 #include <stdbool.h>
2 #include <stdint.h>
3 
4 #include <sys/kconfig.h>
5 #include <sys/kassert.h>
6 #include <sys/kmem.h>
7 #include <sys/mp.h>
8 #include <sys/irq.h>
9 #include <sys/spinlock.h>
10 
11 #include <machine/amd64.h>
12 #include <machine/ioapic.h>
13 #include <machine/lapic.h>
14 #include <machine/trap.h>
15 #include <machine/pmap.h>
16 #include <machine/mp.h>
17 
18 #include <sys/thread.h>
19 #include <sys/disk.h>
20 #include <sys/bufcache.h>
21 #include <sys/vfs.h>
22 #include <sys/elf64.h>
23 
24 #include "../dev/console.h"
25 
26 extern void KTime_Init();
27 extern void KTimer_Init();
28 extern void RTC_Init();
29 extern void PS2_Init();
30 extern void PCI_Init();
31 extern void IDE_Init();
32 extern void MachineBoot_AddMem();
33 extern void Loader_LoadInit();
34 extern void PAlloc_LateInit();
35 
36 #define GDT_MAX 8
37 
38 static SegmentDescriptor GDT[MAX_CPUS][GDT_MAX];
39 static PseudoDescriptor GDTDescriptor[MAX_CPUS];
40 TaskStateSegment64 TSS[MAX_CPUS];
41 
42 static char df_stack[4096];
43 
44 /**
45  * Machine_GDTInit --
46  *
47  * Configures the Global Descriptor Table (GDT) that lists all segments and
48  * privilege levels in x86.  64-bit mode uses flat 64-bit segments and doesn't
49  * support offsets and limits except for the special FS/GS segment registers.
50  * We create four segments for the kernel code/data and user code/data.
51  */
52 static void
Machine_GDTInit()53 Machine_GDTInit()
54 {
55     uint64_t offset;
56     uint64_t tmp;
57     int c = CPU();
58 
59     kprintf("Initializing GDT... "); // Caused pagefault??
60 
61     GDT[c][0] = 0x0;
62     GDT[c][1] = 0x00AF9A000000FFFFULL; /* Kernel CS */
63     GDT[c][2] = 0x00CF92000000FFFFULL; /* Kernel DS */
64     GDT[c][3] = 0x0;
65 
66     // TSS
67     offset = (uint64_t)&TSS[c];
68     GDT[c][4] = sizeof(TaskStateSegment64);
69     tmp = offset & 0x00FFFFFF;
70     GDT[c][4] |= (tmp << 16);
71     tmp = offset & 0xFF000000;
72     GDT[c][4] |= (tmp << 56);
73     GDT[c][4] |= 0x89ULL << 40;
74     GDT[c][5] = offset >> 32;
75 
76     GDT[c][6] = 0x00AFFA000000FFFFULL; /* User CS */
77     GDT[c][7] = 0x00CFF2000000FFFFULL; /* User DS */
78 
79     GDTDescriptor[c].off = (uint64_t)&GDT[c];
80     GDTDescriptor[c].lim = 8*GDT_MAX - 1;
81 
82     lgdt(&GDTDescriptor[c]);
83 
84     kprintf("Done!\n");
85 }
86 
87 /**
88  * Machine_TSSInit --
89  *
90  * Configures the Task State Segment (TSS) that specifies the kernel stack
91  * pointer during an interrupt.
92  */
93 static void
Machine_TSSInit()94 Machine_TSSInit()
95 {
96     int c = CPU();
97 
98     kprintf("Initializing TSS... ");
99 
100     TSS[c]._unused0 = 0;
101     TSS[c]._unused1 = 0;
102     TSS[c]._unused2 = 0;
103     TSS[c]._unused3 = 0;
104     TSS[c]._unused4 = 0;
105     TSS[c].ist1 = ((uint64_t)&df_stack) + 4096;
106     TSS[c].ist2 = 0x0;
107     TSS[c].ist3 = 0x0;
108     TSS[c].ist4 = 0x0;
109     TSS[c].ist5 = 0x0;
110     TSS[c].ist6 = 0x0;
111     TSS[c].ist7 = 0x0;
112     TSS[c].rsp0 = ((uint64_t)&df_stack) + 4096;
113     TSS[c].rsp1 = 0;
114     TSS[c].rsp2 = 0;
115 
116     ltr(SEL_TSS);
117 
118     kprintf("Done!\n");
119 }
120 
121 /**
122  * Machine_SyscallInit --
123  *
124  * Configure the model specific registers (MSRs) that specify how to transfer
125  * control to the operating system when the system call instruction is invoked.
126  */
127 static void
Machine_SyscallInit()128 Machine_SyscallInit()
129 {
130     kprintf("Initializing Syscall... ");
131 
132     wrmsr(MSR_STAR, (uint64_t)SEL_KCS << 32 | (uint64_t)SEL_UCS << 48);
133     wrmsr(MSR_LSTAR, 0);
134     wrmsr(MSR_CSTAR, 0);
135     wrmsr(MSR_SFMASK, 0);
136 
137     kprintf("Done!\n");
138 }
139 
140 /**
141  * Machine_EarlyInit --
142  *
143  * Initializes early kernel state.
144  */
145 void
Machine_EarlyInit()146 Machine_EarlyInit()
147 {
148     Spinlock_EarlyInit();
149     Critical_Init();
150     Critical_Enter();
151     WaitChannel_EarlyInit();
152     Console_Init();
153     PAlloc_Init();
154 }
155 
156 static void
Machine_IdleThread(void * test)157 Machine_IdleThread(void *test)
158 {
159     while (1) { enable_interrupts(); hlt(); }
160 }
161 
162 /**
163  * Machine_Init --
164  *
165  * At this point the assembly startup code has setup temporary processor data
166  * structures sufficient to execute C code and make it through this
167  * initialization routine.
168  */
Machine_Init()169 void Machine_Init()
170 {
171     /*
172      * Initialize Processor State
173      */
174     Machine_GDTInit();
175     Machine_TSSInit();
176     Trap_Init();
177     Machine_SyscallInit();
178     clts(); // Enable FPU/XMM
179 
180     /*
181      * Initialize Memory Allocation and Virtual Memory
182      */
183     PAlloc_AddRegion(DMPA2VA(16*1024*1024), 16*1024*1024);
184     PMap_Init();
185     XMem_Init();
186     PAlloc_LateInit();
187     MachineBoot_AddMem();
188 
189     /*
190      * Initialize Time Keeping
191      */
192     KTime_Init();
193     RTC_Init(); // Finishes initializing KTime
194 
195     /*
196      * Initialize Interrupts
197      */
198     IRQ_Init();
199     LAPIC_Init();
200     IOAPIC_Init();
201     IOAPIC_Enable(0); // Enable timer interrupts
202     Thread_Init();
203 
204     KTimer_Init(); // Depends on RTC and KTime
205 
206     /*
207      * Initialize Additional Processors
208      */
209     MP_Init();
210 
211     /*
212      * Initialize Basic Devices
213      */
214     PS2_Init(); // PS2 Keyboard
215     PCI_Init(); // PCI BUS
216     IDE_Init(); // IDE Disk Controller
217     BufCache_Init();
218 
219     /*
220      * Open the primary disk and mount the root file system
221      */
222     Disk *root = Disk_GetByID(0, 0);
223     if (!root)
224 	Panic("No boot disk!");
225     VFS_MountRoot(root);
226 
227     Critical_Exit();
228 
229     /*
230      * Create the idle thread
231      */
232     Thread *thr = Thread_KThreadCreate(&Machine_IdleThread, NULL);
233     if (thr == NULL) {
234 	kprintf("Couldn't create idle thread!\n");
235     }
236     Sched_SetRunnable(thr);
237 
238     /*
239      * Load the init processor
240      */
241     Loader_LoadInit();
242 
243     breakpoint();
244 }
245 
246 /**
247  * Machine_InitAP --
248  *
249  * Shorter initialization routine for co-processors.
250  */
Machine_InitAP()251 void Machine_InitAP()
252 {
253     Critical_Enter();
254 
255     // Setup CPU state
256     Trap_InitAP();
257     PMap_InitAP();
258     Machine_GDTInit();
259     Machine_TSSInit();
260     Machine_SyscallInit();
261     clts(); // Enable FPU/XMM
262 
263     // Setup LAPIC
264     LAPIC_Init();
265 
266     // Boot processor
267     MP_InitAP();
268     Thread_InitAP();
269     Critical_Exit();
270 
271     Machine_IdleThread(NULL);
272 }
273 
274