1/*
2 * Copyright 2008-2011, Michael Lotz, mmlr@mlotz.ch.
3 * Copyright 2010, Clemens Zeidler, haiku@clemens-zeidler.de.
4 * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
5 * Copyright 2002-2010, Axel D��rfler, axeld@pinc-software.de.
6 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
7 * Distributed under the terms of the MIT License.
8 *
9 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
10 * Distributed under the terms of the NewOS License.
11 */
12
13
14#include <arch/x86/descriptors.h>
15
16#include <stdio.h>
17
18#include <boot/kernel_args.h>
19#include <cpu.h>
20#include <int.h>
21#include <tls.h>
22#include <vm/vm.h>
23#include <vm/vm_priv.h>
24
25#include <arch/int.h>
26#include <arch/user_debugger.h>
27
28#include "interrupts.h"
29
30
31static interrupt_descriptor* sIDTs[B_MAX_CPU_COUNT];
32
33// table with functions handling respective interrupts
34typedef void interrupt_handler_function(struct iframe* frame);
35
36static const uint32 kInterruptHandlerTableSize = 256;
37interrupt_handler_function* gInterruptHandlerTable[kInterruptHandlerTableSize];
38
39segment_descriptor* gGDT;
40
41
42/*!	Initializes a descriptor in an IDT.
43*/
44static void
45set_gate(interrupt_descriptor *gate_addr, addr_t addr, int type, int dpl)
46{
47	unsigned int gate1; // first byte of gate desc
48	unsigned int gate2; // second byte of gate desc
49
50	gate1 = (KERNEL_CODE_SEG << 16) | (0x0000ffff & addr);
51	gate2 = (0xffff0000 & addr) | 0x8000 | (dpl << 13) | (type << 8);
52
53	gate_addr->a = gate1;
54	gate_addr->b = gate2;
55}
56
57
58/*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
59	specified CPU to an interrupt-gate descriptor with the given procedure
60	address.
61	For CPUs other than the boot CPU it must not be called before
62	arch_int_init_post_vm().
63*/
64static void
65set_interrupt_gate(int32 cpu, int n, void (*addr)())
66{
67	set_gate(&sIDTs[cpu][n], (addr_t)addr, 14, DPL_KERNEL);
68}
69
70
71/*!	Initializes the descriptor for interrupt vector \a n in the IDT of the
72	specified CPU to an trap-gate descriptor with the given procedure address.
73	For CPUs other than the boot CPU it must not be called before
74	arch_int_init_post_vm().
75*/
76static void
77set_trap_gate(int32 cpu, int n, void (*addr)())
78{
79	set_gate(&sIDTs[cpu][n], (unsigned int)addr, 15, DPL_USER);
80}
81
82
83/*!	Initializes the descriptor for interrupt vector \a n in the IDT of CPU
84	\a cpu to a task-gate descripter referring to the TSS segment identified
85	by TSS segment selector \a segment.
86	For CPUs other than the boot CPU it must not be called before
87	arch_int_init_post_vm() (arch_cpu_init_post_vm() is fine).
88*/
89static void
90set_task_gate(int32 cpu, int32 n, int32 segment)
91{
92	sIDTs[cpu][n].a = (segment << 16);
93	sIDTs[cpu][n].b = 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
94}
95
96
97static void
98load_tss(int cpu)
99{
100	short seg = (TSS_SEGMENT(cpu) << 3) | DPL_KERNEL;
101	asm("ltr %%ax" : : "a" (seg));
102}
103
104
105//	#pragma mark - Double fault handling
106
107
108void
109x86_double_fault_exception(struct iframe* frame)
110{
111	int cpu = x86_double_fault_get_cpu();
112
113	// The double fault iframe contains no useful information (as
114	// per Intel's architecture spec). Thus we simply save the
115	// information from the (unhandlable) exception which caused the
116	// double in our iframe. This will result even in useful stack
117	// traces. Only problem is that we trust that at least the
118	// TSS is still accessible.
119	struct tss *tss = &gCPU[cpu].arch.tss;
120
121	frame->cs = tss->cs;
122	frame->es = tss->es;
123	frame->ds = tss->ds;
124	frame->fs = tss->fs;
125	frame->gs = tss->gs;
126	frame->ip = tss->eip;
127	frame->bp = tss->ebp;
128	frame->sp = tss->esp;
129	frame->ax = tss->eax;
130	frame->bx = tss->ebx;
131	frame->cx = tss->ecx;
132	frame->dx = tss->edx;
133	frame->si = tss->esi;
134	frame->di = tss->edi;
135	frame->flags = tss->eflags;
136
137	// Use a special handler for page faults which avoids the triple fault
138	// pitfalls.
139	set_interrupt_gate(cpu, 14, &trap14_double_fault);
140
141	debug_double_fault(cpu);
142}
143
144
145void
146x86_page_fault_exception_double_fault(struct iframe* frame)
147{
148	addr_t cr2 = x86_read_cr2();
149
150	// Only if this CPU has a fault handler, we're allowed to be here.
151	cpu_ent& cpu = gCPU[x86_double_fault_get_cpu()];
152	addr_t faultHandler = cpu.fault_handler;
153	if (faultHandler != 0) {
154		debug_set_page_fault_info(cr2, frame->ip,
155			(frame->error_code & 0x2) != 0 ? DEBUG_PAGE_FAULT_WRITE : 0);
156		frame->ip = faultHandler;
157		frame->bp = cpu.fault_handler_stack_pointer;
158		return;
159	}
160
161	// No fault handler. This is bad. Since we originally came from a double
162	// fault, we don't try to reenter the kernel debugger. Instead we just
163	// print the info we've got and enter an infinite loop.
164	kprintf("Page fault in double fault debugger without fault handler! "
165		"Touching address %p from eip %p. Entering infinite loop...\n",
166		(void*)cr2, (void*)frame->ip);
167
168	while (true);
169}
170
171
172static void
173init_double_fault(int cpuNum)
174{
175	// set up the double fault TSS
176	struct tss* tss = &gCPU[cpuNum].arch.double_fault_tss;
177
178	memset(tss, 0, sizeof(struct tss));
179	size_t stackSize;
180	tss->sp0 = (addr_t)x86_get_double_fault_stack(cpuNum, &stackSize);
181	tss->sp0 += stackSize;
182	tss->ss0 = KERNEL_DATA_SEG;
183	tss->cr3 = x86_read_cr3();
184		// copy the current cr3 to the double fault cr3
185	tss->eip = (uint32)&double_fault;
186	tss->es = KERNEL_DATA_SEG;
187	tss->cs = KERNEL_CODE_SEG;
188	tss->ss = KERNEL_DATA_SEG;
189	tss->esp = tss->sp0;
190	tss->ds = KERNEL_DATA_SEG;
191	tss->fs = KERNEL_DATA_SEG;
192	tss->gs = KERNEL_DATA_SEG;
193	tss->ldt_seg_selector = 0;
194	tss->io_map_base = sizeof(struct tss);
195
196	// add TSS descriptor for this new TSS
197	uint16 tssSegmentDescriptorIndex = DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum;
198	set_tss_descriptor(&gGDT[tssSegmentDescriptorIndex],
199		(addr_t)tss, sizeof(struct tss));
200
201	set_task_gate(cpuNum, 8, tssSegmentDescriptorIndex << 3);
202}
203
204
205//	#pragma mark -
206
207
208void
209x86_descriptors_init(kernel_args* args)
210{
211	uint32 i;
212	interrupt_handler_function** table;
213
214	// Get the GDT and boot CPU IDT set up by the boot loader.
215	gGDT = (segment_descriptor*)args->arch_args.vir_gdt;
216	sIDTs[0] = (interrupt_descriptor *)(addr_t)args->arch_args.vir_idt;
217
218	set_interrupt_gate(0, 0, &trap0);
219	set_interrupt_gate(0, 1, &trap1);
220	set_interrupt_gate(0, 2, &trap2);
221	set_trap_gate(0, 3, &trap3);
222	set_interrupt_gate(0, 4, &trap4);
223	set_interrupt_gate(0, 5, &trap5);
224	set_interrupt_gate(0, 6, &trap6);
225	set_interrupt_gate(0, 7, &trap7);
226	// trap8 (double fault) is set in init_double_fault().
227	set_interrupt_gate(0, 9, &trap9);
228	set_interrupt_gate(0, 10, &trap10);
229	set_interrupt_gate(0, 11, &trap11);
230	set_interrupt_gate(0, 12, &trap12);
231	set_interrupt_gate(0, 13, &trap13);
232	set_interrupt_gate(0, 14, &trap14);
233//	set_interrupt_gate(0, 15, &trap15);
234	set_interrupt_gate(0, 16, &trap16);
235	set_interrupt_gate(0, 17, &trap17);
236	set_interrupt_gate(0, 18, &trap18);
237	set_interrupt_gate(0, 19, &trap19);
238
239	// legacy or ioapic interrupts
240	set_interrupt_gate(0, 32, &trap32);
241	set_interrupt_gate(0, 33, &trap33);
242	set_interrupt_gate(0, 34, &trap34);
243	set_interrupt_gate(0, 35, &trap35);
244	set_interrupt_gate(0, 36, &trap36);
245	set_interrupt_gate(0, 37, &trap37);
246	set_interrupt_gate(0, 38, &trap38);
247	set_interrupt_gate(0, 39, &trap39);
248	set_interrupt_gate(0, 40, &trap40);
249	set_interrupt_gate(0, 41, &trap41);
250	set_interrupt_gate(0, 42, &trap42);
251	set_interrupt_gate(0, 43, &trap43);
252	set_interrupt_gate(0, 44, &trap44);
253	set_interrupt_gate(0, 45, &trap45);
254	set_interrupt_gate(0, 46, &trap46);
255	set_interrupt_gate(0, 47, &trap47);
256
257	// additional ioapic interrupts
258	set_interrupt_gate(0, 48, &trap48);
259	set_interrupt_gate(0, 49, &trap49);
260	set_interrupt_gate(0, 50, &trap50);
261	set_interrupt_gate(0, 51, &trap51);
262	set_interrupt_gate(0, 52, &trap52);
263	set_interrupt_gate(0, 53, &trap53);
264	set_interrupt_gate(0, 54, &trap54);
265	set_interrupt_gate(0, 55, &trap55);
266
267	// configurable msi or msi-x interrupts
268	set_interrupt_gate(0, 56, &trap56);
269	set_interrupt_gate(0, 57, &trap57);
270	set_interrupt_gate(0, 58, &trap58);
271	set_interrupt_gate(0, 59, &trap59);
272	set_interrupt_gate(0, 60, &trap60);
273	set_interrupt_gate(0, 61, &trap61);
274	set_interrupt_gate(0, 62, &trap62);
275	set_interrupt_gate(0, 63, &trap63);
276	set_interrupt_gate(0, 64, &trap64);
277	set_interrupt_gate(0, 65, &trap65);
278	set_interrupt_gate(0, 66, &trap66);
279	set_interrupt_gate(0, 67, &trap67);
280	set_interrupt_gate(0, 68, &trap68);
281	set_interrupt_gate(0, 69, &trap69);
282	set_interrupt_gate(0, 70, &trap70);
283	set_interrupt_gate(0, 71, &trap71);
284	set_interrupt_gate(0, 72, &trap72);
285	set_interrupt_gate(0, 73, &trap73);
286	set_interrupt_gate(0, 74, &trap74);
287	set_interrupt_gate(0, 75, &trap75);
288	set_interrupt_gate(0, 76, &trap76);
289	set_interrupt_gate(0, 77, &trap77);
290	set_interrupt_gate(0, 78, &trap78);
291	set_interrupt_gate(0, 79, &trap79);
292	set_interrupt_gate(0, 80, &trap80);
293	set_interrupt_gate(0, 81, &trap81);
294	set_interrupt_gate(0, 82, &trap82);
295	set_interrupt_gate(0, 83, &trap83);
296	set_interrupt_gate(0, 84, &trap84);
297	set_interrupt_gate(0, 85, &trap85);
298	set_interrupt_gate(0, 86, &trap86);
299	set_interrupt_gate(0, 87, &trap87);
300	set_interrupt_gate(0, 88, &trap88);
301	set_interrupt_gate(0, 89, &trap89);
302	set_interrupt_gate(0, 90, &trap90);
303	set_interrupt_gate(0, 91, &trap91);
304	set_interrupt_gate(0, 92, &trap92);
305	set_interrupt_gate(0, 93, &trap93);
306	set_interrupt_gate(0, 94, &trap94);
307	set_interrupt_gate(0, 95, &trap95);
308	set_interrupt_gate(0, 96, &trap96);
309	set_interrupt_gate(0, 97, &trap97);
310
311	set_trap_gate(0, 98, &trap98);	// for performance testing only
312	set_trap_gate(0, 99, &trap99);	// syscall interrupt
313
314	reserve_io_interrupt_vectors(2, 98);
315
316	// configurable msi or msi-x interrupts
317	set_interrupt_gate(0, 100, &trap100);
318	set_interrupt_gate(0, 101, &trap101);
319	set_interrupt_gate(0, 102, &trap102);
320	set_interrupt_gate(0, 103, &trap103);
321	set_interrupt_gate(0, 104, &trap104);
322	set_interrupt_gate(0, 105, &trap105);
323	set_interrupt_gate(0, 106, &trap106);
324	set_interrupt_gate(0, 107, &trap107);
325	set_interrupt_gate(0, 108, &trap108);
326	set_interrupt_gate(0, 109, &trap109);
327	set_interrupt_gate(0, 110, &trap110);
328	set_interrupt_gate(0, 111, &trap111);
329	set_interrupt_gate(0, 112, &trap112);
330	set_interrupt_gate(0, 113, &trap113);
331	set_interrupt_gate(0, 114, &trap114);
332	set_interrupt_gate(0, 115, &trap115);
333	set_interrupt_gate(0, 116, &trap116);
334	set_interrupt_gate(0, 117, &trap117);
335	set_interrupt_gate(0, 118, &trap118);
336	set_interrupt_gate(0, 119, &trap119);
337	set_interrupt_gate(0, 120, &trap120);
338	set_interrupt_gate(0, 121, &trap121);
339	set_interrupt_gate(0, 122, &trap122);
340	set_interrupt_gate(0, 123, &trap123);
341	set_interrupt_gate(0, 124, &trap124);
342	set_interrupt_gate(0, 125, &trap125);
343	set_interrupt_gate(0, 126, &trap126);
344	set_interrupt_gate(0, 127, &trap127);
345	set_interrupt_gate(0, 128, &trap128);
346	set_interrupt_gate(0, 129, &trap129);
347	set_interrupt_gate(0, 130, &trap130);
348	set_interrupt_gate(0, 131, &trap131);
349	set_interrupt_gate(0, 132, &trap132);
350	set_interrupt_gate(0, 133, &trap133);
351	set_interrupt_gate(0, 134, &trap134);
352	set_interrupt_gate(0, 135, &trap135);
353	set_interrupt_gate(0, 136, &trap136);
354	set_interrupt_gate(0, 137, &trap137);
355	set_interrupt_gate(0, 138, &trap138);
356	set_interrupt_gate(0, 139, &trap139);
357	set_interrupt_gate(0, 140, &trap140);
358	set_interrupt_gate(0, 141, &trap141);
359	set_interrupt_gate(0, 142, &trap142);
360	set_interrupt_gate(0, 143, &trap143);
361	set_interrupt_gate(0, 144, &trap144);
362	set_interrupt_gate(0, 145, &trap145);
363	set_interrupt_gate(0, 146, &trap146);
364	set_interrupt_gate(0, 147, &trap147);
365	set_interrupt_gate(0, 148, &trap148);
366	set_interrupt_gate(0, 149, &trap149);
367	set_interrupt_gate(0, 150, &trap150);
368	set_interrupt_gate(0, 151, &trap151);
369	set_interrupt_gate(0, 152, &trap152);
370	set_interrupt_gate(0, 153, &trap153);
371	set_interrupt_gate(0, 154, &trap154);
372	set_interrupt_gate(0, 155, &trap155);
373	set_interrupt_gate(0, 156, &trap156);
374	set_interrupt_gate(0, 157, &trap157);
375	set_interrupt_gate(0, 158, &trap158);
376	set_interrupt_gate(0, 159, &trap159);
377	set_interrupt_gate(0, 160, &trap160);
378	set_interrupt_gate(0, 161, &trap161);
379	set_interrupt_gate(0, 162, &trap162);
380	set_interrupt_gate(0, 163, &trap163);
381	set_interrupt_gate(0, 164, &trap164);
382	set_interrupt_gate(0, 165, &trap165);
383	set_interrupt_gate(0, 166, &trap166);
384	set_interrupt_gate(0, 167, &trap167);
385	set_interrupt_gate(0, 168, &trap168);
386	set_interrupt_gate(0, 169, &trap169);
387	set_interrupt_gate(0, 170, &trap170);
388	set_interrupt_gate(0, 171, &trap171);
389	set_interrupt_gate(0, 172, &trap172);
390	set_interrupt_gate(0, 173, &trap173);
391	set_interrupt_gate(0, 174, &trap174);
392	set_interrupt_gate(0, 175, &trap175);
393	set_interrupt_gate(0, 176, &trap176);
394	set_interrupt_gate(0, 177, &trap177);
395	set_interrupt_gate(0, 178, &trap178);
396	set_interrupt_gate(0, 179, &trap179);
397	set_interrupt_gate(0, 180, &trap180);
398	set_interrupt_gate(0, 181, &trap181);
399	set_interrupt_gate(0, 182, &trap182);
400	set_interrupt_gate(0, 183, &trap183);
401	set_interrupt_gate(0, 184, &trap184);
402	set_interrupt_gate(0, 185, &trap185);
403	set_interrupt_gate(0, 186, &trap186);
404	set_interrupt_gate(0, 187, &trap187);
405	set_interrupt_gate(0, 188, &trap188);
406	set_interrupt_gate(0, 189, &trap189);
407	set_interrupt_gate(0, 190, &trap190);
408	set_interrupt_gate(0, 191, &trap191);
409	set_interrupt_gate(0, 192, &trap192);
410	set_interrupt_gate(0, 193, &trap193);
411	set_interrupt_gate(0, 194, &trap194);
412	set_interrupt_gate(0, 195, &trap195);
413	set_interrupt_gate(0, 196, &trap196);
414	set_interrupt_gate(0, 197, &trap197);
415	set_interrupt_gate(0, 198, &trap198);
416	set_interrupt_gate(0, 199, &trap199);
417	set_interrupt_gate(0, 200, &trap200);
418	set_interrupt_gate(0, 201, &trap201);
419	set_interrupt_gate(0, 202, &trap202);
420	set_interrupt_gate(0, 203, &trap203);
421	set_interrupt_gate(0, 204, &trap204);
422	set_interrupt_gate(0, 205, &trap205);
423	set_interrupt_gate(0, 206, &trap206);
424	set_interrupt_gate(0, 207, &trap207);
425	set_interrupt_gate(0, 208, &trap208);
426	set_interrupt_gate(0, 209, &trap209);
427	set_interrupt_gate(0, 210, &trap210);
428	set_interrupt_gate(0, 211, &trap211);
429	set_interrupt_gate(0, 212, &trap212);
430	set_interrupt_gate(0, 213, &trap213);
431	set_interrupt_gate(0, 214, &trap214);
432	set_interrupt_gate(0, 215, &trap215);
433	set_interrupt_gate(0, 216, &trap216);
434	set_interrupt_gate(0, 217, &trap217);
435	set_interrupt_gate(0, 218, &trap218);
436	set_interrupt_gate(0, 219, &trap219);
437	set_interrupt_gate(0, 220, &trap220);
438	set_interrupt_gate(0, 221, &trap221);
439	set_interrupt_gate(0, 222, &trap222);
440	set_interrupt_gate(0, 223, &trap223);
441	set_interrupt_gate(0, 224, &trap224);
442	set_interrupt_gate(0, 225, &trap225);
443	set_interrupt_gate(0, 226, &trap226);
444	set_interrupt_gate(0, 227, &trap227);
445	set_interrupt_gate(0, 228, &trap228);
446	set_interrupt_gate(0, 229, &trap229);
447	set_interrupt_gate(0, 230, &trap230);
448	set_interrupt_gate(0, 231, &trap231);
449	set_interrupt_gate(0, 232, &trap232);
450	set_interrupt_gate(0, 233, &trap233);
451	set_interrupt_gate(0, 234, &trap234);
452	set_interrupt_gate(0, 235, &trap235);
453	set_interrupt_gate(0, 236, &trap236);
454	set_interrupt_gate(0, 237, &trap237);
455	set_interrupt_gate(0, 238, &trap238);
456	set_interrupt_gate(0, 239, &trap239);
457	set_interrupt_gate(0, 240, &trap240);
458	set_interrupt_gate(0, 241, &trap241);
459	set_interrupt_gate(0, 242, &trap242);
460	set_interrupt_gate(0, 243, &trap243);
461	set_interrupt_gate(0, 244, &trap244);
462	set_interrupt_gate(0, 245, &trap245);
463	set_interrupt_gate(0, 246, &trap246);
464	set_interrupt_gate(0, 247, &trap247);
465	set_interrupt_gate(0, 248, &trap248);
466	set_interrupt_gate(0, 249, &trap249);
467	set_interrupt_gate(0, 250, &trap250);
468
469	// smp / apic local interrupts
470	set_interrupt_gate(0, 251, &trap251);
471	set_interrupt_gate(0, 252, &trap252);
472	set_interrupt_gate(0, 253, &trap253);
473	set_interrupt_gate(0, 254, &trap254);
474	set_interrupt_gate(0, 255, &trap255);
475
476	// init interrupt handler table
477	table = gInterruptHandlerTable;
478
479	// defaults
480	for (i = 0; i < ARCH_INTERRUPT_BASE; i++)
481		table[i] = x86_invalid_exception;
482	for (i = ARCH_INTERRUPT_BASE; i < kInterruptHandlerTableSize; i++)
483		table[i] = x86_hardware_interrupt;
484
485	table[0] = x86_unexpected_exception;	// Divide Error Exception (#DE)
486	table[1] = x86_handle_debug_exception;	// Debug Exception (#DB)
487	table[2] = x86_fatal_exception;			// NMI Interrupt
488	table[3] = x86_handle_breakpoint_exception; // Breakpoint Exception (#BP)
489	table[4] = x86_unexpected_exception;	// Overflow Exception (#OF)
490	table[5] = x86_unexpected_exception;	// BOUND Range Exceeded Exception (#BR)
491	table[6] = x86_unexpected_exception;	// Invalid Opcode Exception (#UD)
492	table[7] = x86_fatal_exception;			// Device Not Available Exception (#NM)
493	table[8] = x86_double_fault_exception;	// Double Fault Exception (#DF)
494	table[9] = x86_fatal_exception;			// Coprocessor Segment Overrun
495	table[10] = x86_fatal_exception;		// Invalid TSS Exception (#TS)
496	table[11] = x86_fatal_exception;		// Segment Not Present (#NP)
497	table[12] = x86_fatal_exception;		// Stack Fault Exception (#SS)
498	table[13] = x86_unexpected_exception;	// General Protection Exception (#GP)
499	table[14] = x86_page_fault_exception;	// Page-Fault Exception (#PF)
500	table[16] = x86_unexpected_exception;	// x87 FPU Floating-Point Error (#MF)
501	table[17] = x86_unexpected_exception;	// Alignment Check Exception (#AC)
502	table[18] = x86_fatal_exception;		// Machine-Check Exception (#MC)
503	table[19] = x86_unexpected_exception;	// SIMD Floating-Point Exception (#XF)
504}
505
506
507void
508x86_descriptors_init_percpu(kernel_args* args, int cpu)
509{
510	// load the TSS for this cpu
511	// note the main cpu gets initialized in x86_descriptors_init_post_vm()
512	if (cpu != 0) {
513		load_tss(cpu);
514
515		// set the IDT
516		struct {
517			uint16	limit;
518			void*	address;
519		} _PACKED descriptor = {
520			256 * 8 - 1,	// 256 descriptors, 8 bytes each (-1 for "limit")
521			sIDTs[cpu]
522		};
523
524		asm volatile("lidt	%0" : : "m"(descriptor));
525	}
526}
527
528
529status_t
530x86_descriptors_init_post_vm(kernel_args* args)
531{
532	uint32 i;
533
534	// account for the segment descriptors
535	create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
536		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
537
538	// create IDT area for the boot CPU
539	area_id area = create_area("idt", (void**)&sIDTs[0], B_EXACT_ADDRESS,
540		B_PAGE_SIZE, B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
541	if (area < B_OK)
542		return area;
543
544	// create IDTs for the off-boot CPU
545	size_t idtSize = 256 * 8;
546		// 256 8 bytes-sized descriptors
547	if (args->num_cpus > 0) {
548		size_t areaSize = ROUNDUP(args->num_cpus * idtSize, B_PAGE_SIZE);
549		interrupt_descriptor* idt;
550		virtual_address_restrictions virtualRestrictions = {};
551		virtualRestrictions.address_specification = B_ANY_KERNEL_ADDRESS;
552		physical_address_restrictions physicalRestrictions = {};
553		area = create_area_etc(B_SYSTEM_TEAM, "idt", areaSize, B_CONTIGUOUS,
554			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, CREATE_AREA_DONT_WAIT,
555			0, &virtualRestrictions, &physicalRestrictions, (void**)&idt);
556		if (area < 0)
557			return area;
558
559		for (i = 1; i < args->num_cpus; i++) {
560			sIDTs[i] = idt;
561			memcpy(idt, sIDTs[0], idtSize);
562			idt += 256;
563			// The CPU's IDTR will be set in arch_cpu_init_percpu().
564		}
565	}
566
567	// setup task-state segments
568	for (i = 0; i < args->num_cpus; i++) {
569		// initialize the regular and double fault tss stored in the per-cpu
570		// structure
571		memset(&gCPU[i].arch.tss, 0, sizeof(struct tss));
572		gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG;
573		gCPU[i].arch.tss.io_map_base = sizeof(struct tss);
574
575		// add TSS descriptor for this new TSS
576		set_tss_descriptor(&gGDT[TSS_SEGMENT(i)], (addr_t)&gCPU[i].arch.tss,
577			sizeof(struct tss));
578
579		// initialize the double fault tss
580		init_double_fault(i);
581	}
582
583	// set the current hardware task on cpu 0
584	load_tss(0);
585
586	// setup TLS descriptors (one for every CPU)
587
588	for (i = 0; i < args->num_cpus; i++) {
589		set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE,
590			DT_DATA_WRITEABLE, DPL_USER);
591	}
592
593	return B_OK;
594}
595