2 ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
5 #include <kernel/kernel.h>
7 #include <kernel/debug.h>
8 #include <kernel/console.h>
9 #include <kernel/int.h>
10 #include <kernel/thread.h>
11 #include <kernel/smp.h>
12 #include <kernel/syscalls.h>
13 #include <kernel/vm_priv.h>
15 #include <kernel/arch/cpu.h>
16 #include <kernel/arch/int.h>
17 #include <kernel/arch/faults.h>
18 #include <kernel/arch/vm.h>
19 #include <kernel/arch/smp.h>
21 #include <kernel/arch/i386/interrupts.h>
22 #include <kernel/arch/i386/faults.h>
24 #include <boot/stage2.h>
30 #define SYSCALL_VECTOR 99
32 static desc_table
*idt
= NULL
;
34 static void interrupt_ack(int n
)
36 if(n
>= 0x20 && n
< 0x30) {
37 // 8239 controlled interrupt
39 out8(0x20, 0xa0); // EOI to pic 2
40 out8(0x20, 0x20); // EOI to pic 1
44 static void _set_gate(desc_table
*gate_addr
, unsigned int addr_t
, int type
, int dpl
)
46 unsigned int gate1
; // first byte of gate desc
47 unsigned int gate2
; // second byte of gate desc
49 gate1
= (KERNEL_CODE_SEG
<< 16) | (0x0000ffff & addr_t
);
50 gate2
= (0xffff0000 & addr_t
) | 0x8000 | (dpl
<< 13) | (type
<< 8);
56 void arch_int_enable_io_interrupt(int irq
)
58 if(irq
< 0x20 || irq
>= 0x30) return;
60 // if this is a external interrupt via 8239, enable it here
62 out8(in8(0x21) & ~(1 << irq
), 0x21);
64 out8(in8(0xa1) & ~(1 << (irq
- 8)), 0xa1);
67 void arch_int_disable_io_interrupt(int irq
)
69 if(irq
< 0x20 || irq
>= 0x30) return;
71 // if this is a external interrupt via 8239, disable it here
73 out8(in8(0x21) | (1 << irq
), 0x21);
75 out8(in8(0xa1) | (1 << (irq
- 8)), 0xa1);
78 void i386_set_task_gate(int n
, uint32 seg
)
80 idt
[n
].a
= (seg
<< 16); // tss segment in 31:16
81 idt
[n
].b
= 0x8000 | (0 << 13) | (0x5 << 8); // present, dpl 0, type 5
84 static void set_intr_gate(int n
, void *addr_t
)
86 _set_gate(&idt
[n
], (unsigned int)addr_t
, 14, 0);
91 static void set_trap_gate(int n
, void *addr_t
)
93 _set_gate(&idt
[n
], (unsigned int)addr_t
, 15, 0);
97 static void set_system_gate(int n
, void *addr_t
)
99 _set_gate(&idt
[n
], (unsigned int)addr_t
, 15, 3);
102 void arch_int_enable_interrupts(void)
107 void arch_int_disable_interrupts(void)
112 bool arch_int_are_interrupts_enabled(void)
117 "popl %0;\n" : "=g" (flags
));
118 return flags
& 0x200 ? 1 : 0;
121 void i386_handle_trap(struct iframe frame
); /* keep the compiler happy, this function must be called only from assembly */
122 void i386_handle_trap(struct iframe frame
)
124 int ret
= INT_NO_RESCHEDULE
;
125 bool adjust_int_disable_count
= false;
126 struct thread
*t
= thread_get_current_thread();
129 i386_push_iframe(t
, &frame
);
130 if(frame
.vector
!= SYSCALL_VECTOR
) {
131 adjust_int_disable_count
= true;
132 t
->int_disable_level
++; // make it look like the ints were disabled
136 // if(frame.vector != 0x20)
137 // dprintf("i386_handle_trap: vector 0x%x, ip 0x%x, cpu %d\n", frame.vector, frame.eip, smp_get_current_cpu());
138 switch(frame
.vector
) {
140 ret
= i386_double_fault(frame
.error_code
);
143 ret
= i386_general_protection_fault(frame
.error_code
);
149 asm ("movl %%cr2, %0" : "=r" (cr2
) );
151 if(!kernel_startup
&& (frame
.flags
& 0x200) == 0) {
152 // ints are were disabled when the page fault was taken, that is very bad
153 panic("i386_handle_trap: page fault at 0x%x, ip 0x%x, write %d with ints disabled\n",
154 cr2
, frame
.eip
, (frame
.error_code
& 0x2) != 0);
157 if(!kernel_startup
) {
158 int_restore_interrupts(); // should enable the interrupts
159 adjust_int_disable_count
= false;
160 ASSERT(int_are_interrupts_enabled());
164 ret
= vm_page_fault(cr2
, frame
.eip
,
165 (frame
.error_code
& 0x2) != 0,
166 (frame
.error_code
& 0x4) != 0,
169 // the page fault handler wants us to modify the iframe to set the
170 // IP the cpu will return to to be this ip
175 case SYSCALL_VECTOR
: {
177 unsigned int args
[MAX_ARGS
];
181 thread_atkernel_entry();
187 dprintf("i386_handle_trap: syscall %d, count %d, ptr 0x%x\n", frame
.eax
, frame
.ecx
, frame
.edx
);
188 dprintf(" call stack:\n");
189 for(i
=0; i
<frame
.ecx
; i
++)
190 dprintf("\t0x%x\n", ((unsigned int *)frame
.edx
)[i
]);
194 ** syscall interface works as such:
196 ** ecx has number of args (0-16)
197 ** edx has pointer to buffer containing args from first to last
198 ** each is verified to make sure someone doesn't try to clobber it
200 if(frame
.ecx
<= MAX_ARGS
) {
201 if((addr_t
)frame
.edx
>= KERNEL_BASE
&& (addr_t
)frame
.edx
<= KERNEL_TOP
) {
202 retcode
= ERR_VM_BAD_USER_MEMORY
;
204 rc
= user_memcpy(args
, (void *)frame
.edx
, frame
.ecx
* sizeof(unsigned int));
206 retcode
= ERR_VM_BAD_USER_MEMORY
;
208 ret
= syscall_dispatcher(frame
.eax
, (void *)args
, &retcode
);
211 // want to pass too many args into the system
212 retcode
= ERR_INVALID_ARGS
;
214 frame
.eax
= retcode
& 0xffffffff;
215 frame
.edx
= retcode
>> 32;
219 if(frame
.vector
>= 0x20) {
220 interrupt_ack(frame
.vector
); // ack the 8239 (if applicable)
221 ret
= int_io_interrupt_handler(frame
.vector
);
223 panic("i386_handle_trap: unhandled cpu trap 0x%x at ip 0x%x!\n", frame
.vector
, frame
.eip
);
224 ret
= INT_NO_RESCHEDULE
;
229 if(ret
== INT_RESCHEDULE
) {
230 int_disable_interrupts();
233 RELEASE_THREAD_LOCK();
234 int_restore_interrupts();
237 if(frame
.cs
== USER_CODE_SEG
|| frame
.vector
== SYSCALL_VECTOR
) {
238 thread_atkernel_exit();
240 // dprintf("0x%x cpu %d!\n", thread_get_current_thread_id(), smp_get_current_cpu());
244 if(adjust_int_disable_count
)
245 t
->int_disable_level
--; // keep the count in sync
249 int arch_int_init(kernel_args
*ka
)
251 idt
= (desc_table
*)ka
->arch_args
.vir_idt
;
253 // setup the interrupt controller
254 out8(0x11, 0x20); // Start initialization sequence for #1.
255 out8(0x11, 0xa0); // ...and #2.
256 out8(0x20, 0x21); // Set start of interrupts for #1 (0x20).
257 out8(0x28, 0xa1); // Set start of interrupts for #2 (0x28).
258 out8(0x04, 0x21); // Set #1 to be the master.
259 out8(0x02, 0xa1); // Set #2 to be the slave.
260 out8(0x01, 0x21); // Set both to operate in 8086 mode.
262 out8(0xfb, 0x21); // Mask off all interrupts (except slave pic line).
263 out8(0xff, 0xa1); // Mask off interrupts on the slave.
265 set_intr_gate(0, &trap0
);
266 set_intr_gate(1, &trap1
);
267 set_intr_gate(2, &trap2
);
268 set_intr_gate(3, &trap3
);
269 set_intr_gate(4, &trap4
);
270 set_intr_gate(5, &trap5
);
271 set_intr_gate(6, &trap6
);
272 set_intr_gate(7, &trap7
);
273 // set_intr_gate(8, &trap8); /* handled below by pointing the idt entry to a tss segment */
274 set_intr_gate(9, &trap9
);
275 set_intr_gate(10, &trap10
);
276 set_intr_gate(11, &trap11
);
277 set_intr_gate(12, &trap12
);
278 set_intr_gate(13, &trap13
);
279 set_intr_gate(14, &trap14
);
280 // set_intr_gate(15, &trap15);
281 set_intr_gate(16, &trap16
);
282 set_intr_gate(17, &trap17
);
283 set_intr_gate(18, &trap18
);
285 set_intr_gate(32, &trap32
);
286 set_intr_gate(33, &trap33
);
287 set_intr_gate(34, &trap34
);
288 set_intr_gate(35, &trap35
);
289 set_intr_gate(36, &trap36
);
290 set_intr_gate(37, &trap37
);
291 set_intr_gate(38, &trap38
);
292 set_intr_gate(39, &trap39
);
293 set_intr_gate(40, &trap40
);
294 set_intr_gate(41, &trap41
);
295 set_intr_gate(42, &trap42
);
296 set_intr_gate(43, &trap43
);
297 set_intr_gate(44, &trap44
);
298 set_intr_gate(45, &trap45
);
299 set_intr_gate(46, &trap46
);
300 set_intr_gate(47, &trap47
);
302 set_system_gate(SYSCALL_VECTOR
, &trap99
);
304 set_intr_gate(251, &trap251
);
305 set_intr_gate(252, &trap252
);
306 set_intr_gate(253, &trap253
);
307 set_intr_gate(254, &trap254
);
308 set_intr_gate(255, &trap255
);
313 int arch_int_init2(kernel_args
*ka
)
315 idt
= (desc_table
*)ka
->arch_args
.vir_idt
;
316 vm_create_anonymous_region(vm_get_kernel_aspace_id(), "idt", (void *)&idt
,
317 REGION_ADDR_EXACT_ADDRESS
, PAGE_SIZE
, REGION_WIRING_WIRED_ALREADY
, LOCK_RW
|LOCK_KERNEL
);